Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84027cbae1 | ||
|
|
5343040ef3 | ||
|
|
75cd7dd4b9 | ||
|
|
fb6ffd8e09 | ||
|
|
aca9e61f39 | ||
|
|
56078098a4 | ||
|
|
1f197965e0 | ||
|
|
183f0f6c42 | ||
|
|
76624c7d83 | ||
|
|
ab47c56ec5 | ||
|
|
ad35ed96c8 | ||
|
|
97bd51cf5f | ||
|
|
f4a110cfd7 | ||
|
|
e9ed06adfd | ||
|
|
bc5eaf34fe | ||
|
|
3e8b891dd0 | ||
|
|
3f2ea4bc64 | ||
|
|
ae81b37c1d | ||
|
|
b4349afb1b | ||
|
|
0cffe8e3f7 | ||
|
|
7a1f4f9abe | ||
|
|
5768b01786 | ||
|
|
7e9079467f | ||
|
|
615e96922e | ||
|
|
8b94c452fb | ||
|
|
66dd510acc | ||
|
|
96e044566c | ||
|
|
726ad84d7f | ||
|
|
4fc422f880 | ||
|
|
1938024ab3 | ||
|
|
05b1de6fd5 | ||
|
|
0bf8807b50 | ||
|
|
23668ee74e | ||
|
|
6bc5c5a808 | ||
|
|
330004dc72 | ||
|
|
a900d6d742 | ||
|
|
bfea70eec9 | ||
|
|
13babbf330 | ||
|
|
0a6fe382ac | ||
|
|
dd6dea9dfc | ||
|
|
11434fba68 | ||
|
|
10bf90c92a | ||
|
|
5193fe4bab | ||
|
|
4df4995623 | ||
|
|
f5f4ecf46a | ||
|
|
69b65d06a4 | ||
|
|
e6bf4e836d | ||
|
|
01d67eb239 | ||
|
|
3514cfbd44 | ||
|
|
cade35fe10 | ||
|
|
2c6df77f5a | ||
|
|
0276ae91b5 | ||
|
|
60fee2accb | ||
|
|
03e2632294 | ||
|
|
194fe59458 | ||
|
|
e400111f8a | ||
|
|
8bc7607783 | ||
|
|
4108451ebe | ||
|
|
0f56257aa1 | ||
|
|
2a575284b9 | ||
|
|
444bcbfb30 | ||
|
|
212021c878 | ||
|
|
600b687253 | ||
|
|
ae3aada172 | ||
|
|
50cc8af8c3 | ||
|
|
1809cdbf37 | ||
|
|
fb38047769 | ||
|
|
08e0d6a34a | ||
|
|
b4fddaec7f | ||
|
|
3f19d22941 | ||
|
|
c7d51cfc4c | ||
|
|
6829d34e90 | ||
|
|
021e430103 | ||
|
|
ae6f42a7fb | ||
|
|
da98097394 | ||
|
|
43f0b935cf | ||
|
|
db5d14e0ce | ||
|
|
b25cf5eadb | ||
|
|
bd3b41c809 | ||
|
|
31d301064a | ||
|
|
b95b9bdaf3 | ||
|
|
937f0b5687 | ||
|
|
ffbc892e44 | ||
|
|
9e872932d1 | ||
|
|
ecb2fbf900 | ||
|
|
72edd2e15d | ||
|
|
c3d22c554f | ||
|
|
e72f4a1582 | ||
|
|
5e43c060fa | ||
|
|
e8dee1ddd9 | ||
|
|
d85b8c776f | ||
|
|
fb518b6218 | ||
|
|
8d510cde21 | ||
|
|
da4bf167ee | ||
|
|
dc1abf8dcb | ||
|
|
3fc969a50b | ||
|
|
4064129d49 | ||
|
|
22b4e0bfff | ||
|
|
53fa1f88fd | ||
|
|
5fefcd92f3 | ||
|
|
d20bc936da | ||
|
|
e79f036a70 | ||
|
|
0f2af91a04 | ||
|
|
7e361cb3f1 | ||
|
|
1f7acd4027 | ||
|
|
dddca7bf4b | ||
|
|
e520be80c0 | ||
|
|
0b78dedf04 | ||
|
|
8f409477c8 | ||
|
|
9c22f7ce69 | ||
|
|
05fa916915 | ||
|
|
9a593d7a61 | ||
|
|
30017eeaa0 | ||
|
|
9b03cacc94 | ||
|
|
557970cf54 | ||
|
|
d90dac60ef | ||
|
|
b4b2e67260 | ||
|
|
bcd5e935e7 | ||
|
|
b322627609 | ||
|
|
09861095ff | ||
|
|
47e567fb40 | ||
|
|
5bb30ad28f | ||
|
|
a46bbf05ec | ||
|
|
04a4705dbd | ||
|
|
3271c96531 | ||
|
|
05fa6b9aba | ||
|
|
7edd7f27cb | ||
|
|
4a6b12eda1 | ||
|
|
a354e1a0eb | ||
|
|
c2c419522a | ||
|
|
7a3cc7d242 | ||
|
|
bd6f02f6af | ||
|
|
bd33728fd7 | ||
|
|
8400ee8a3d | ||
|
|
80ee7aef8e | ||
|
|
41762be3a5 | ||
|
|
605dda7b76 | ||
|
|
8d6e3b5a58 | ||
|
|
53920fc368 | ||
|
|
96d10423d9 | ||
|
|
42be9b5b51 | ||
|
|
0add041516 | ||
|
|
dee76cac8d | ||
|
|
9646fab22c | ||
|
|
a54e9cb244 | ||
|
|
f8339c7a9a | ||
|
|
9e2c864117 | ||
|
|
e1ccd71455 | ||
|
|
0e82426ea1 | ||
|
|
6c7afd168a | ||
|
|
e014fdf3da | ||
|
|
2074da05c8 | ||
|
|
84cd87b70a | ||
|
|
75f87044f6 | ||
|
|
f71b51e64a | ||
|
|
9d741cdd63 | ||
|
|
56be17000a | ||
|
|
f6aacbc31d | ||
|
|
ad4b57c327 | ||
|
|
3794b2f0de | ||
|
|
e0e8412728 | ||
|
|
05b8175aad | ||
|
|
339c89dd1c | ||
|
|
402299e9c8 | ||
|
|
d0e8f450fd | ||
|
|
e97b1ccd7a | ||
|
|
68691b91ef | ||
|
|
213d417481 | ||
|
|
2ec841eb61 | ||
|
|
60b5c54be1 | ||
|
|
448412a191 | ||
|
|
e06327936e | ||
|
|
5f044e1aed | ||
|
|
d90fb6fc9b | ||
|
|
1c583d2ea9 | ||
|
|
ddab131102 | ||
|
|
3b06cf8a2a | ||
|
|
c5d7c29f3d | ||
|
|
26af860eac | ||
|
|
ec9852eb98 | ||
|
|
f2b8c6d0ca | ||
|
|
2cf7a048cf | ||
|
|
3dbb71a076 | ||
|
|
ddf6760543 | ||
|
|
a6fa323f33 | ||
|
|
2df8f1acdb | ||
|
|
74a3290abc |
@@ -8,13 +8,13 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
## 在提交问题之前,请确认以下事项:
|
||||
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide.html) 以及 [常见问题](https://clash-verge-rev.github.io/faq.html)
|
||||
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide/term.html) 以及 [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
||||
2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似issue,否则请在已有的issue下进行讨论
|
||||
3. 请 **务必** 给issue填写一个简洁明了的标题,以便他人快速检索
|
||||
4. 请 **务必** 先下载 [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) 版本测试,确保问题依然存在
|
||||
5. 请 **务必** 按照模板规范详细描述问题,否则issue将会被关闭
|
||||
## Before submitting the issue, please make sure of the following checklist:
|
||||
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide.html) and [FAQ](https://clash-verge-rev.github.io/faq.html)
|
||||
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide/term.html) and [FAQ](https://clash-verge-rev.github.io/faq/windows.html)
|
||||
2. Please make sure there is no similar issue in the [existing issues](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue), otherwise please discuss under the existing issue
|
||||
3. Please be sure to fill in a concise and clear title for the issue so that others can quickly search
|
||||
4. Please be sure to download the [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) version for testing to ensure that the problem still exists
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
contact_links:
|
||||
- name: 讨论交流 / Communication
|
||||
url: https://t.me/clash_verge_rev
|
||||
about: 在 Telegram 群组中与其他用户讨论交流 / Communicate with other users in the Telegram group
|
||||
@@ -8,13 +8,13 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
## 在提交问题之前,请确认以下事项:
|
||||
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide.html) 确认软件不存在类似的功能
|
||||
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide/term.html) 确认软件不存在类似的功能
|
||||
2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似issue,否则请在已有的issue下进行讨论
|
||||
3. 请 **务必** 给issue填写一个简洁明了的标题,以便他人快速检索
|
||||
4. 请 **务必** 先下载 [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) 版本测试,确保该功能还未实现
|
||||
5. 请 **务必** 按照模板规范详细描述问题,否则issue将会被关闭
|
||||
## Before submitting the issue, please make sure of the following checklist:
|
||||
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide.html) to confirm that the software does not have similar functions
|
||||
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide/term.html) to confirm that the software does not have similar functions
|
||||
2. Please make sure there is no similar issue in the [existing issues](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue), otherwise please discuss under the existing issue
|
||||
3. Please be sure to fill in a concise and clear title for the issue so that others can quickly search
|
||||
4. Please be sure to download the [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) version for testing to ensure that the function has not been implemented
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
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" ]; then
|
||||
pnpm build --target $INPUT_TARGET
|
||||
else
|
||||
pnpm build --target $INPUT_TARGET -b deb
|
||||
fi
|
||||
|
||||
cargo tauri build --target $INPUT_TARGET
|
||||
|
||||
@@ -5,11 +5,19 @@ tar -Jxvf ./node-v20.10.0-linux-x64.tar.xz
|
||||
export PATH=$(pwd)/node-v20.10.0-linux-x64/bin:$PATH
|
||||
npm install pnpm -g
|
||||
|
||||
cargo install --git https://github.com/tauri-apps/tauri --branch 1.x tauri-cli
|
||||
|
||||
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
|
||||
dpkg --add-architecture arm64
|
||||
apt-get update
|
||||
|
||||
@@ -18,6 +18,8 @@ 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
|
||||
@@ -31,7 +33,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust Stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
uses: dtolnay/rust-toolchain@1.77.0
|
||||
|
||||
- name: Add Rust Target
|
||||
run: rustup target add ${{ matrix.target }}
|
||||
@@ -41,15 +43,17 @@ jobs:
|
||||
with:
|
||||
workspaces: src-tauri
|
||||
|
||||
- name: Install Tauri CLI
|
||||
run: cargo install --git https://github.com/tauri-apps/tauri --branch 1.x tauri-cli
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- uses: pnpm/action-setup@v3
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Pnpm install and check
|
||||
@@ -60,16 +64,23 @@ jobs:
|
||||
- name: Tauri build
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
with:
|
||||
tagName: alpha
|
||||
releaseName: "Clash Verge Rev Alpha"
|
||||
releaseBody: "More new features are now supported."
|
||||
releaseDraft: false
|
||||
prerelease: true
|
||||
tauriScript: pnpm
|
||||
tauriScript: cargo tauri
|
||||
args: --target ${{ matrix.target }}
|
||||
|
||||
- name: Portable Bundle
|
||||
@@ -77,8 +88,6 @@ jobs:
|
||||
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:
|
||||
@@ -87,6 +96,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
|
||||
@@ -99,6 +110,7 @@ jobs:
|
||||
- name: Build for Linux
|
||||
uses: ./.github/build-for-linux
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
with:
|
||||
@@ -111,52 +123,107 @@ jobs:
|
||||
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
||||
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
||||
|
||||
- run: |
|
||||
cat > release.txt << 'EOF'
|
||||
### 我应该下载哪个版本?
|
||||
|
||||
- Windows x86_64架构: x64-setup.exe (不支持win7)
|
||||
- Windows arm64架构: arm64-setup.exe
|
||||
- MacOS intel芯片: x64.dmg
|
||||
- MacOS apple M芯片: aarch64.dmg (提示文件损坏看下面FAQ)
|
||||
- Linux x64架构: amd64.AppImage/amd64.deb
|
||||
- Linux arm64架构: arm64.deb
|
||||
- Linux armv7架构: armhf.deb
|
||||
- Windows 便携板 x86_64架构: x64_portable.zip (不推荐使用,无法自动更新)
|
||||
- Windows 便携板 arm64架构: arm64_portable.zip (不推荐使用,无法自动更新)
|
||||
|
||||
### FAQ
|
||||
|
||||
- [https://clash-verge-rev.github.io/faq.html](https://clash-verge-rev.github.io/faq.html)
|
||||
|
||||
Created at ${{ env.BUILDTIME }}.
|
||||
EOF
|
||||
|
||||
- name: Upload Release
|
||||
if: startsWith(matrix.target, 'x86_64')
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: alpha
|
||||
name: "Clash Verge Rev Alpha"
|
||||
body_path: release.txt
|
||||
body: "More new features are now supported."
|
||||
prerelease: true
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: src-tauri/target/${{ matrix.target }}/release/bundle/appimage/*.AppImage*
|
||||
files: |
|
||||
src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
|
||||
src-tauri/target/${{ matrix.target }}/release/bundle/rpm/*.rpm
|
||||
|
||||
alpha-for-fixed-webview2:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
arch: x64
|
||||
- os: windows-latest
|
||||
target: i686-pc-windows-msvc
|
||||
arch: x86
|
||||
- os: windows-latest
|
||||
target: aarch64-pc-windows-msvc
|
||||
arch: arm64
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Add Rust Target
|
||||
run: rustup target add ${{ matrix.target }}
|
||||
|
||||
- name: Rust Cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: src-tauri
|
||||
|
||||
- name: Install Tauri CLI
|
||||
run: cargo install --git https://github.com/tauri-apps/tauri --branch 1.x tauri-cli
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
- name: Pnpm install and check
|
||||
run: |
|
||||
pnpm i
|
||||
pnpm check ${{ matrix.target }}
|
||||
|
||||
- name: Download WebView2 Runtime
|
||||
run: |
|
||||
invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/109.0.1518.78/Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab
|
||||
Expand .\Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -F:* ./src-tauri
|
||||
Remove-Item .\src-tauri\tauri.windows.conf.json
|
||||
Rename-Item .\src-tauri\webview2.${{ matrix.arch }}.json tauri.windows.conf.json
|
||||
|
||||
- name: Tauri build
|
||||
id: build
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
with:
|
||||
tauriScript: cargo tauri
|
||||
args: --target ${{ matrix.target }}
|
||||
|
||||
- name: Rename
|
||||
run: |
|
||||
Rename-Item '.\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\Clash Verge_${{steps.build.outputs.appVersion}}_${{ matrix.arch }}-setup.exe' 'Clash Verge_${{steps.build.outputs.appVersion}}_${{ matrix.arch }}_fixed_webview2-setup.exe'
|
||||
Rename-Item '.\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\Clash Verge_${{steps.build.outputs.appVersion}}_${{ matrix.arch }}-setup.nsis.zip' 'Clash Verge_${{steps.build.outputs.appVersion}}_${{ matrix.arch }}_fixed_webview2-setup.nsis.zip'
|
||||
Rename-Item '.\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\Clash Verge_${{steps.build.outputs.appVersion}}_${{ matrix.arch }}-setup.nsis.zip.sig' 'Clash Verge_${{steps.build.outputs.appVersion}}_${{ matrix.arch }}_fixed_webview2-setup.nsis.zip.sig'
|
||||
|
||||
- name: Upload Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: alpha
|
||||
name: "Clash Verge Rev Alpha"
|
||||
body_path: release.txt
|
||||
body: "More new features are now supported."
|
||||
prerelease: true
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
|
||||
files: src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*setup*
|
||||
|
||||
- name: Portable Bundle
|
||||
run: pnpm portable-fixed-webview2 ${{ matrix.target }} --alpha
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
update_tag:
|
||||
name: Update tag
|
||||
runs-on: ubuntu-latest
|
||||
needs: [alpha, alpha-for-linux]
|
||||
needs: [alpha, alpha-for-linux, alpha-for-fixed-webview2]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
@@ -175,27 +242,41 @@ jobs:
|
||||
|
||||
- run: |
|
||||
cat > release.txt << 'EOF'
|
||||
### 我应该下载哪个版本?
|
||||
## 我应该下载哪个版本?
|
||||
|
||||
- Windows x86_64架构: x64-setup.exe (不支持win7)
|
||||
- Windows arm64架构: arm64-setup.exe
|
||||
### MacOS (提示文件损坏或开发者无法验证请查看下面FAQ)
|
||||
- MacOS intel芯片: x64.dmg
|
||||
- MacOS apple M芯片: aarch64.dmg (提示文件损坏看下面FAQ)
|
||||
- Linux x64架构: amd64.AppImage/amd64.deb
|
||||
- Linux arm64架构: arm64.deb
|
||||
- Linux armv7架构: armhf.deb
|
||||
- Windows 便携板 x86_64架构: x64_portable.zip (不推荐使用,无法自动更新)
|
||||
- Windows 便携板 arm64架构: arm64_portable.zip (不推荐使用,无法自动更新)
|
||||
- MacOS apple M芯片: aarch64.dmg
|
||||
|
||||
### Linux
|
||||
- Linux 64位: amd64.deb/amd64.rpm
|
||||
- Linux 32位: i386.deb/i386.rpm
|
||||
- Linux arm64架构: arm64.deb/aarch64.rpm
|
||||
- Linux armv7架构: armhf.deb/armhfp.rpm
|
||||
|
||||
### Windows (Win7 用户请查看下面FAQ中的解决方案)
|
||||
#### 正常版本(推荐)
|
||||
- 64位: x64-setup.exe
|
||||
- 32位: x86-setup.exe
|
||||
- arm64架构: arm64-setup.exe
|
||||
#### 便携版(不推荐使用,无法自动更新)
|
||||
- 64位: x64_portable.zip
|
||||
- 32位: x86_portable.zip
|
||||
- arm64架构: arm64_portable.zip
|
||||
#### 内置Webview2版(体积较大,仅在企业版系统或Win7无法安装webview2时使用)
|
||||
- 64位: x64_fixed_webview2-setup.exe
|
||||
- 32位: x86_fixed_webview2-setup.exe
|
||||
- arm64架构: arm64_fixed_webview2-setup.exe
|
||||
|
||||
### FAQ
|
||||
|
||||
- [https://clash-verge-rev.github.io/faq.html](https://clash-verge-rev.github.io/faq.html)
|
||||
- [FAQ](https://clash-verge-rev.github.io/faq/windows.html)
|
||||
|
||||
Created at ${{ env.BUILDTIME }}.
|
||||
EOF
|
||||
|
||||
- name: Upload Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: alpha
|
||||
name: "Clash Verge Rev Alpha"
|
||||
|
||||
@@ -15,6 +15,8 @@ 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
|
||||
@@ -28,7 +30,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust Stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
uses: dtolnay/rust-toolchain@1.77.0
|
||||
|
||||
- name: Add Rust Target
|
||||
run: rustup target add ${{ matrix.target }}
|
||||
@@ -43,10 +45,9 @@ jobs:
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- uses: pnpm/action-setup@v3
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Pnpm install and check
|
||||
@@ -57,15 +58,20 @@ jobs:
|
||||
- name: Tauri build
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
with:
|
||||
tagName: v__VERSION__
|
||||
releaseName: "Clash Verge Rev v__VERSION__"
|
||||
releaseBody: "More new features are now supported."
|
||||
releaseDraft: false
|
||||
prerelease: false
|
||||
tauriScript: pnpm
|
||||
args: --target ${{ matrix.target }}
|
||||
|
||||
@@ -74,8 +80,6 @@ jobs:
|
||||
run: pnpm portable ${{ matrix.target }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
|
||||
release-for-linux:
|
||||
strategy:
|
||||
@@ -84,6 +88,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
|
||||
@@ -96,6 +102,7 @@ jobs:
|
||||
- name: Build for Linux
|
||||
uses: ./.github/build-for-linux
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
with:
|
||||
@@ -108,40 +115,112 @@ jobs:
|
||||
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
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: 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*
|
||||
files: |
|
||||
src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
|
||||
src-tauri/target/${{ matrix.target }}/release/bundle/rpm/*.rpm
|
||||
|
||||
release-for-fixed-webview2:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
arch: x64
|
||||
- os: windows-latest
|
||||
target: i686-pc-windows-msvc
|
||||
arch: x86
|
||||
- os: windows-latest
|
||||
target: aarch64-pc-windows-msvc
|
||||
arch: arm64
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- 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@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
- name: Pnpm install and check
|
||||
run: |
|
||||
pnpm i
|
||||
pnpm check ${{ matrix.target }}
|
||||
|
||||
- name: Download WebView2 Runtime
|
||||
run: |
|
||||
invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/109.0.1518.78/Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab
|
||||
Expand .\Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -F:* ./src-tauri
|
||||
Remove-Item .\src-tauri\tauri.windows.conf.json
|
||||
Rename-Item .\src-tauri\webview2.${{ matrix.arch }}.json tauri.windows.conf.json
|
||||
|
||||
- name: Tauri build
|
||||
id: build
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
with:
|
||||
tauriScript: pnpm
|
||||
args: --target ${{ matrix.target }}
|
||||
|
||||
- name: Rename
|
||||
run: |
|
||||
Rename-Item '.\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\Clash Verge_${{steps.build.outputs.appVersion}}_${{ matrix.arch }}-setup.exe' 'Clash Verge_${{steps.build.outputs.appVersion}}_${{ matrix.arch }}_fixed_webview2-setup.exe'
|
||||
Rename-Item '.\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\Clash Verge_${{steps.build.outputs.appVersion}}_${{ matrix.arch }}-setup.nsis.zip' 'Clash Verge_${{steps.build.outputs.appVersion}}_${{ matrix.arch }}_fixed_webview2-setup.nsis.zip'
|
||||
Rename-Item '.\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\Clash Verge_${{steps.build.outputs.appVersion}}_${{ matrix.arch }}-setup.nsis.zip.sig' 'Clash Verge_${{steps.build.outputs.appVersion}}_${{ matrix.arch }}_fixed_webview2-setup.nsis.zip.sig'
|
||||
|
||||
- name: Upload Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: v${{env.VERSION}}
|
||||
name: "Clash Verge Rev v${{env.VERSION}}"
|
||||
tag_name: v${{steps.build.outputs.appVersion}}
|
||||
name: "Clash Verge Rev v${{steps.build.outputs.appVersion}}"
|
||||
body: "More new features are now supported."
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
|
||||
files: src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*setup*
|
||||
|
||||
- name: Portable Bundle
|
||||
run: pnpm portable-fixed-webview2 ${{ matrix.target }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
release-update:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [release, release-for-linux]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Pnpm install
|
||||
@@ -151,3 +230,28 @@ jobs:
|
||||
run: pnpm updater
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
release-update-for-fixed-webview2:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [release-for-fixed-webview2]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
- name: Pnpm install
|
||||
run: pnpm i
|
||||
|
||||
- name: Release updater file
|
||||
run: pnpm updater-fixed-webview2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -7,17 +7,16 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Pnpm install
|
||||
@@ -27,3 +26,27 @@ jobs:
|
||||
run: pnpm updater
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
release-update-for-fixed-webview2:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
- name: Pnpm install
|
||||
run: pnpm i
|
||||
|
||||
- name: Release updater file
|
||||
run: pnpm updater-fixed-webview2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
node_modules
|
||||
.pnpm-store
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
@@ -6,4 +7,4 @@ dist-ssr
|
||||
update.json
|
||||
scripts/_env.sh
|
||||
.vscode
|
||||
.tool-version
|
||||
.tool-versions
|
||||
@@ -1,5 +1,5 @@
|
||||
<h1 align="center">
|
||||
<img src="./src/assets/image/logo.png" alt="Clash" width="128" />
|
||||
<img src="./src-tauri/icons/icon.png" alt="Clash" width="128" />
|
||||
<br>
|
||||
Continuation of <a href="https://github.com/zzzgydi/clash-verge">Clash Verge</a>
|
||||
<br>
|
||||
@@ -11,7 +11,9 @@ A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">Tauri</a
|
||||
|
||||
## Preview
|
||||
|
||||

|
||||
| Dark | Light |
|
||||
| -------------------------------- | --------------------------------- |
|
||||
|  |  |
|
||||
|
||||
## Install
|
||||
|
||||
@@ -49,7 +51,7 @@ Supports Windows (x64/x86), Linux (x64/arm64) and macOS 10.15+ (intel/apple).
|
||||
|
||||
### FAQ
|
||||
|
||||
Refer to [Doc FAQ Page](https://clash-verge-rev.github.io/faq.html)
|
||||
Refer to [Doc FAQ Page](https://clash-verge-rev.github.io/faq/windows.html)
|
||||
|
||||
## Development
|
||||
|
||||
|
||||
@@ -1,4 +1,144 @@
|
||||
## 1.5.10
|
||||
## v1.6.6
|
||||
|
||||
### Features
|
||||
|
||||
- MacOS 应用签名
|
||||
- 删除 AppImage
|
||||
- 应用更新对话框添加下载按钮
|
||||
- 设置系统代理绕过时保留默认值
|
||||
- 系统代理绕过设置输入格式检查
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- MacOS 代理组图标无法显示
|
||||
- RPM 包依赖缺失
|
||||
|
||||
---
|
||||
|
||||
## v1.6.5
|
||||
|
||||
### Features
|
||||
|
||||
- 添加 RPM 包支持
|
||||
- 优化细节
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- MacOS 10.15 编辑器空白的问题
|
||||
- MacOS 低版本启动白屏的问题
|
||||
|
||||
---
|
||||
|
||||
## v1.6.4
|
||||
|
||||
### Features
|
||||
|
||||
- 系统代理支持 PAC 模式
|
||||
- 允许关闭不使用的端口
|
||||
- 使用新的应用图标
|
||||
- MacOS 支持切换托盘图标单色/彩色模式
|
||||
- CSS 注入支持通过编辑器编辑
|
||||
- 优化代理组列表性能
|
||||
- 优化流量图显性能
|
||||
- 支持波斯语
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- Kill 内核后 Tun 开启缓慢的问题
|
||||
- 代理绕过为空时使用默认值
|
||||
- 无法读取剪切板内容
|
||||
- Windows 下覆盖安装无法内核占用问题
|
||||
|
||||
---
|
||||
|
||||
## v1.6.2
|
||||
|
||||
### Features
|
||||
|
||||
- 支持本地文件拖拽导入
|
||||
- 重新支持 32 位 CPU
|
||||
- 新增内置 Webview2 版本
|
||||
- 优化 Merge 逻辑,支持深度合并
|
||||
- 删除 Merge 配置中的 append/prepend-provider 字段
|
||||
- 支持更新稳定版内核
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- MacOS DNS 还原失败
|
||||
- CMD 环境变量格式错误
|
||||
- Linux 下与 N 卡的兼容性问题
|
||||
- 修改 Tun 设置不立即生效
|
||||
|
||||
---
|
||||
|
||||
## v1.6.1
|
||||
|
||||
### Features
|
||||
|
||||
- 鼠标悬浮显示当前订阅的名称 [#938](https://github.com/clash-verge-rev/clash-verge-rev/pull/938)
|
||||
- 日志过滤支持正则表达式 [#959](https://github.com/clash-verge-rev/clash-verge-rev/pull/959)
|
||||
- 更新 Clash 内核到 1.18.4
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- 修复 Linux KDE 环境下系统代理无法开启的问题
|
||||
- 窗口最大化图标调整 [#924](https://github.com/clash-verge-rev/clash-verge-rev/pull/924)
|
||||
- 修改 MacOS 托盘点击行为(左键菜单,右键点击事件)
|
||||
- 修复 MacOS 服务模式安装失败的问题
|
||||
|
||||
---
|
||||
|
||||
## v1.6.0
|
||||
|
||||
### Features
|
||||
|
||||
- Meta(mihomo)内核回退 1.18.1(当前新版内核 hy2 协议有 bug,等修复后更新)
|
||||
- 多处界面细节调整 [#724](https://github.com/clash-verge-rev/clash-verge-rev/pull/724) [#799](https://github.com/clash-verge-rev/clash-verge-rev/pull/799) [#900](https://github.com/clash-verge-rev/clash-verge-rev/pull/900) [#901](https://github.com/clash-verge-rev/clash-verge-rev/pull/901)
|
||||
- Linux 下新增服务模式
|
||||
- 新增订阅卡片右键可以打开机场首页
|
||||
- url-test 支持手动选择、节点组 fixed 节点使用角标展示 [#840](https://github.com/clash-verge-rev/clash-verge-rev/pull/840)
|
||||
- Clash 配置、Merge 配置提供 JSON Schema 语法支持、连接界面调整 [#887](https://github.com/clash-verge-rev/clash-verge-rev/pull/887)
|
||||
- 修改 Merge 配置文件默认内容 [#889](https://github.com/clash-verge-rev/clash-verge-rev/pull/889)
|
||||
- 修改 tun 模式默认 mtu 为 1500,老版本升级,需在 tun 模式设置下“重置为默认值”。
|
||||
- 使用 npm 安装 meta-json-schema [#895](https://github.com/clash-verge-rev/clash-verge-rev/pull/895)
|
||||
- 更新部分翻译 [#904](https://github.com/clash-verge-rev/clash-verge-rev/pull/904)
|
||||
- 支持 ico 格式的任务栏图标
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- 修复 Linux KDE 环境下系统代理无法开启的问题
|
||||
- 修复延迟检测动画问题
|
||||
- 窗口最大化图标调整 [#816](https://github.com/clash-verge-rev/clash-verge-rev/pull/816)
|
||||
- 修复 Windows 某些情况下无法安装服务模式 [#822](https://github.com/clash-verge-rev/clash-verge-rev/pull/822)
|
||||
- UI 细节修复 [#821](https://github.com/clash-verge-rev/clash-verge-rev/pull/821)
|
||||
- 修复使用默认编辑器打开配置文件
|
||||
- 修复内核文件在特定目录也可以更新的问题 [#857](https://github.com/clash-verge-rev/clash-verge-rev/pull/857)
|
||||
- 修复服务模式的安装目录问题
|
||||
- 修复删除配置文件的“更新间隔”出现的问题 [#907](https://github.com/clash-verge-rev/clash-verge-rev/issues/907)
|
||||
|
||||
### 已知问题(历史遗留问题,暂未找到有效解决方案)
|
||||
|
||||
- MacOS M 芯片下服务模式无法安装;临时解决方案:在内核 ⚙️ 下,手动授权,再打开 tun 模式。
|
||||
- MacOS 下如果删除过网络配置,会导致无法正常打开系统代理;临时解决方案:使用浏览器代理插件或手动配置系统代理。
|
||||
- Window 拨号连接下无法正确识别并打开系统代理;临时解决方案:使用浏览器代理插件或使用 tun 模式。
|
||||
|
||||
---
|
||||
|
||||
## v1.5.11
|
||||
|
||||
### Features
|
||||
|
||||
- Meta(mihomo)内核更新 1.18.2
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- 升级图标无法点击的问题
|
||||
- 卸载时检查安装目录是否为空
|
||||
- 代理界面图标重合的问题
|
||||
|
||||
---
|
||||
|
||||
## v1.5.10
|
||||
|
||||
### Features
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 576 KiB |
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 162 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clash-verge",
|
||||
"version": "1.5.10",
|
||||
"version": "1.6.6",
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
"dev": "tauri dev",
|
||||
@@ -12,52 +12,59 @@
|
||||
"web:serve": "vite preview",
|
||||
"check": "node scripts/check.mjs",
|
||||
"updater": "node scripts/updater.mjs",
|
||||
"updater-fixed-webview2": "node scripts/updater-fixed-webview2.mjs",
|
||||
"portable": "node scripts/portable.mjs",
|
||||
"portable-fixed-webview2": "node scripts/portable-fixed-webview2.mjs",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.1.0",
|
||||
"@dnd-kit/sortable": "^8.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@emotion/react": "^11.11.3",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/styled": "^11.11.5",
|
||||
"@juggle/resize-observer": "^3.4.0",
|
||||
"@mui/icons-material": "^5.15.5",
|
||||
"@mui/icons-material": "^5.15.19",
|
||||
"@mui/lab": "5.0.0-alpha.149",
|
||||
"@mui/material": "^5.15.5",
|
||||
"@mui/x-data-grid": "^6.18.7",
|
||||
"@tauri-apps/api": "^1.5.3",
|
||||
"ahooks": "^3.7.8",
|
||||
"axios": "^1.6.5",
|
||||
"@mui/material": "^5.15.19",
|
||||
"@mui/x-data-grid": "^6.20.1",
|
||||
"@tauri-apps/api": "^1.5.6",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"ahooks": "^3.8.0",
|
||||
"axios": "^1.7.2",
|
||||
"dayjs": "1.11.5",
|
||||
"i18next": "^23.7.16",
|
||||
"foxact": "^0.2.35",
|
||||
"i18next": "^23.11.5",
|
||||
"lodash-es": "^4.17.21",
|
||||
"monaco-editor": "^0.34.1",
|
||||
"nanoid": "^5.0.4",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"meta-json-schema": "1.18.5-alpha4",
|
||||
"monaco-editor": "^0.49.0",
|
||||
"monaco-yaml": "^5.2.0",
|
||||
"nanoid": "^5.0.7",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-error-boundary": "^3.1.4",
|
||||
"react-hook-form": "^7.49.3",
|
||||
"react-hook-form": "^7.51.5",
|
||||
"react-i18next": "^13.5.0",
|
||||
"react-router-dom": "^6.21.2",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-router-dom": "^6.23.1",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"react-virtuoso": "^4.6.2",
|
||||
"recoil": "^0.7.7",
|
||||
"snarkdown": "^2.0.0",
|
||||
"react-virtuoso": "^4.7.11",
|
||||
"swr": "^1.3.0",
|
||||
"tar": "^6.2.0"
|
||||
"tar": "^6.2.1",
|
||||
"types-pac": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@actions/github": "^5.1.1",
|
||||
"@tauri-apps/cli": "^1.5.9",
|
||||
"@tauri-apps/cli": "^1.5.14",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/react": "^18.2.48",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/react-transition-group": "^4.4.10",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"adm-zip": "^0.5.10",
|
||||
"@vitejs/plugin-legacy": "^5.4.1",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"adm-zip": "^0.5.14",
|
||||
"cross-env": "^7.0.3",
|
||||
"fs-extra": "^11.2.0",
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
@@ -65,9 +72,10 @@
|
||||
"node-fetch": "^3.3.2",
|
||||
"prettier": "^2.8.8",
|
||||
"pretty-quick": "^3.3.1",
|
||||
"sass": "^1.70.0",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.11",
|
||||
"sass": "^1.77.5",
|
||||
"terser": "^5.31.1",
|
||||
"typescript": "^5.4.5",
|
||||
"vite": "^5.2.13",
|
||||
"vite-plugin-monaco-editor": "^1.1.0",
|
||||
"vite-plugin-svgr": "^4.2.0"
|
||||
},
|
||||
@@ -76,5 +84,6 @@
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"endOfLine": "lf"
|
||||
}
|
||||
},
|
||||
"packageManager": "pnpm@9.1.4"
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ 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-x64": "mihomo-darwin-amd64-compatible",
|
||||
"darwin-arm64": "mihomo-darwin-arm64",
|
||||
"linux-x64": "mihomo-linux-amd64-compatible",
|
||||
"linux-ia32": "mihomo-linux-386",
|
||||
@@ -108,7 +108,7 @@ 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-x64": "mihomo-darwin-amd64-compatible",
|
||||
"darwin-arm64": "mihomo-darwin-arm64",
|
||||
"linux-x64": "mihomo-linux-amd64-compatible",
|
||||
"linux-ia32": "mihomo-linux-386",
|
||||
@@ -353,27 +353,53 @@ const resolvePlugin = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// service chmod
|
||||
const resolveServicePermission = async () => {
|
||||
const serviceExecutables = [
|
||||
"clash-verge-service",
|
||||
"install-service",
|
||||
"uninstall-service",
|
||||
];
|
||||
const resDir = path.join(cwd, "src-tauri/resources");
|
||||
for (let f of serviceExecutables) {
|
||||
const targetPath = path.join(resDir, f);
|
||||
if (await fs.pathExists(targetPath)) {
|
||||
execSync(`chmod 755 ${targetPath}`);
|
||||
console.log(`[INFO]: "${targetPath}" chmod finished`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* main
|
||||
*/
|
||||
|
||||
const SERVICE_URL = `https://github.com/clash-verge-rev/clash-verge-service/releases/download/${SIDECAR_HOST}`;
|
||||
|
||||
const resolveService = () =>
|
||||
const resolveService = () => {
|
||||
let ext = platform === "win32" ? ".exe" : "";
|
||||
resolveResource({
|
||||
file: "clash-verge-service.exe",
|
||||
downloadURL: `${SERVICE_URL}/clash-verge-service.exe`,
|
||||
file: "clash-verge-service" + ext,
|
||||
downloadURL: `${SERVICE_URL}/clash-verge-service${ext}`,
|
||||
});
|
||||
const resolveInstall = () =>
|
||||
};
|
||||
|
||||
const resolveInstall = () => {
|
||||
let ext = platform === "win32" ? ".exe" : "";
|
||||
resolveResource({
|
||||
file: "install-service.exe",
|
||||
downloadURL: `${SERVICE_URL}/install-service.exe`,
|
||||
file: "install-service" + ext,
|
||||
downloadURL: `${SERVICE_URL}/install-service${ext}`,
|
||||
});
|
||||
const resolveUninstall = () =>
|
||||
};
|
||||
|
||||
const resolveUninstall = () => {
|
||||
let ext = platform === "win32" ? ".exe" : "";
|
||||
resolveResource({
|
||||
file: "uninstall-service.exe",
|
||||
downloadURL: `${SERVICE_URL}/uninstall-service.exe`,
|
||||
file: "uninstall-service" + ext,
|
||||
downloadURL: `${SERVICE_URL}/uninstall-service${ext}`,
|
||||
});
|
||||
};
|
||||
|
||||
const resolveSetDnsScript = () =>
|
||||
resolveResource({
|
||||
file: "set_dns.sh",
|
||||
@@ -420,9 +446,9 @@ const tasks = [
|
||||
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 },
|
||||
{ name: "service", func: resolveService, retry: 5 },
|
||||
{ name: "install", func: resolveInstall, retry: 5 },
|
||||
{ name: "uninstall", func: resolveUninstall, retry: 5 },
|
||||
{ name: "set_dns_script", func: resolveSetDnsScript, retry: 5 },
|
||||
{ name: "unset_dns_script", func: resolveUnSetDnsScript, retry: 5 },
|
||||
{ name: "mmdb", func: resolveMmdb, retry: 5 },
|
||||
@@ -434,12 +460,20 @@ const tasks = [
|
||||
retry: 5,
|
||||
winOnly: true,
|
||||
},
|
||||
{
|
||||
name: "service_chmod",
|
||||
func: resolveServicePermission,
|
||||
retry: 1,
|
||||
unixOnly: true,
|
||||
},
|
||||
];
|
||||
|
||||
async function runTask() {
|
||||
const task = tasks.shift();
|
||||
if (!task) return;
|
||||
if (task.winOnly && process.platform !== "win32") return runTask();
|
||||
if (task.winOnly && platform !== "win32") return runTask();
|
||||
if (task.linuxOnly && platform !== "linux") return runTask();
|
||||
if (task.unixOnly && platform === "win32") return runTask();
|
||||
|
||||
for (let i = 0; i < task.retry; i++) {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import fs from "fs-extra";
|
||||
import path from "path";
|
||||
import AdmZip from "adm-zip";
|
||||
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 = {
|
||||
"x86_64-pc-windows-msvc": "x64",
|
||||
"i686-pc-windows-msvc": "x86",
|
||||
"aarch64-pc-windows-msvc": "arm64",
|
||||
};
|
||||
|
||||
const PROCESS_MAP = {
|
||||
x64: "x64",
|
||||
ia32: "x86",
|
||||
arm64: "arm64",
|
||||
};
|
||||
const arch = target ? ARCH_MAP[target] : PROCESS_MAP[process.arch];
|
||||
/// Script for ci
|
||||
/// 打包绿色版/便携版 (only Windows)
|
||||
async function resolvePortable() {
|
||||
if (process.platform !== "win32") return;
|
||||
|
||||
const releaseDir = target
|
||||
? `./src-tauri/target/${target}/release`
|
||||
: `./src-tauri/target/release`;
|
||||
|
||||
const configDir = path.join(releaseDir, ".config");
|
||||
|
||||
if (!(await fs.pathExists(releaseDir))) {
|
||||
throw new Error("could not found the release dir");
|
||||
}
|
||||
|
||||
await fs.mkdir(configDir);
|
||||
await fs.createFile(path.join(configDir, "PORTABLE"));
|
||||
|
||||
const zip = new AdmZip();
|
||||
|
||||
zip.addLocalFile(path.join(releaseDir, "Clash Verge.exe"));
|
||||
zip.addLocalFile(path.join(releaseDir, "clash-meta.exe"));
|
||||
zip.addLocalFile(path.join(releaseDir, "clash-meta-alpha.exe"));
|
||||
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
|
||||
zip.addLocalFolder(
|
||||
path.join(
|
||||
releaseDir,
|
||||
`Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${arch}`
|
||||
),
|
||||
`Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${arch}`
|
||||
);
|
||||
zip.addLocalFolder(configDir, ".config");
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const packageJson = require("../package.json");
|
||||
const { version } = packageJson;
|
||||
|
||||
const zipFile = `Clash.Verge_${version}_${arch}_fixed_webview2_portable.zip`;
|
||||
zip.writeZip(zipFile);
|
||||
|
||||
console.log("[INFO]: create portable zip successfully");
|
||||
|
||||
// push release assets
|
||||
if (process.env.GITHUB_TOKEN === undefined) {
|
||||
throw new Error("GITHUB_TOKEN is required");
|
||||
}
|
||||
|
||||
const options = { owner: context.repo.owner, repo: context.repo.repo };
|
||||
const github = getOctokit(process.env.GITHUB_TOKEN);
|
||||
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,
|
||||
});
|
||||
|
||||
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({
|
||||
...options,
|
||||
release_id: release.id,
|
||||
name: zipFile,
|
||||
data: zip.toBuffer(),
|
||||
});
|
||||
}
|
||||
|
||||
resolvePortable().catch(console.error);
|
||||
@@ -9,9 +9,16 @@ const alpha = process.argv.slice(2)[1];
|
||||
|
||||
const ARCH_MAP = {
|
||||
"x86_64-pc-windows-msvc": "x64",
|
||||
"i686-pc-windows-msvc": "x86",
|
||||
"aarch64-pc-windows-msvc": "arm64",
|
||||
};
|
||||
|
||||
const PROCESS_MAP = {
|
||||
x64: "x64",
|
||||
ia32: "x86",
|
||||
arm64: "arm64",
|
||||
};
|
||||
const arch = target ? ARCH_MAP[target] : PROCESS_MAP[process.arch];
|
||||
/// Script for ci
|
||||
/// 打包绿色版/便携版 (only Windows)
|
||||
async function resolvePortable() {
|
||||
@@ -41,7 +48,7 @@ async function resolvePortable() {
|
||||
const packageJson = require("../package.json");
|
||||
const { version } = packageJson;
|
||||
|
||||
const zipFile = `Clash.Verge_${version}_${ARCH_MAP[target]}_portable.zip`;
|
||||
const zipFile = `Clash.Verge_${version}_${arch}_portable.zip`;
|
||||
zip.writeZip(zipFile);
|
||||
|
||||
console.log("[INFO]: create portable zip successfully");
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
import fetch from "node-fetch";
|
||||
import { getOctokit, context } from "@actions/github";
|
||||
import { resolveUpdateLog } from "./updatelog.mjs";
|
||||
|
||||
const UPDATE_TAG_NAME = "updater";
|
||||
const UPDATE_JSON_FILE = "update-fixed-webview2.json";
|
||||
const UPDATE_JSON_PROXY = "update-fixed-webview2-proxy.json";
|
||||
|
||||
/// generate update.json
|
||||
/// upload to update tag's release asset
|
||||
async function resolveUpdater() {
|
||||
if (process.env.GITHUB_TOKEN === undefined) {
|
||||
throw new Error("GITHUB_TOKEN is required");
|
||||
}
|
||||
|
||||
const options = { owner: context.repo.owner, repo: context.repo.repo };
|
||||
const github = getOctokit(process.env.GITHUB_TOKEN);
|
||||
|
||||
const { data: tags } = await github.rest.repos.listTags({
|
||||
...options,
|
||||
per_page: 10,
|
||||
page: 1,
|
||||
});
|
||||
|
||||
// get the latest publish tag
|
||||
const tag = tags.find((t) => t.name.startsWith("v"));
|
||||
|
||||
console.log(tag);
|
||||
console.log();
|
||||
|
||||
const { data: latestRelease } = await github.rest.repos.getReleaseByTag({
|
||||
...options,
|
||||
tag: tag.name,
|
||||
});
|
||||
|
||||
const updateData = {
|
||||
name: tag.name,
|
||||
notes: await resolveUpdateLog(tag.name), // use updatelog.md
|
||||
pub_date: new Date().toISOString(),
|
||||
platforms: {
|
||||
"windows-x86_64": { signature: "", url: "" },
|
||||
"windows-aarch64": { signature: "", url: "" },
|
||||
"windows-x86": { signature: "", url: "" },
|
||||
"windows-i686": { signature: "", url: "" },
|
||||
},
|
||||
};
|
||||
|
||||
const promises = latestRelease.assets.map(async (asset) => {
|
||||
const { name, browser_download_url } = asset;
|
||||
|
||||
// win64 url
|
||||
if (name.endsWith("x64_fixed_webview2-setup.nsis.zip")) {
|
||||
updateData.platforms["windows-x86_64"].url = browser_download_url;
|
||||
}
|
||||
// win64 signature
|
||||
if (name.endsWith("x64_fixed_webview2-setup.nsis.zip.sig")) {
|
||||
const sig = await getSignature(browser_download_url);
|
||||
updateData.platforms["windows-x86_64"].signature = sig;
|
||||
}
|
||||
|
||||
// win32 url
|
||||
if (name.endsWith("x86_fixed_webview2-setup.nsis.zip")) {
|
||||
updateData.platforms["windows-x86"].url = browser_download_url;
|
||||
updateData.platforms["windows-i686"].url = browser_download_url;
|
||||
}
|
||||
// win32 signature
|
||||
if (name.endsWith("x86_fixed_webview2-setup.nsis.zip.sig")) {
|
||||
const sig = await getSignature(browser_download_url);
|
||||
updateData.platforms["windows-x86"].signature = sig;
|
||||
updateData.platforms["windows-i686"].signature = sig;
|
||||
}
|
||||
|
||||
// win arm url
|
||||
if (name.endsWith("arm64_fixed_webview2-setup.nsis.zip")) {
|
||||
updateData.platforms["windows-aarch64"].url = browser_download_url;
|
||||
}
|
||||
// win arm signature
|
||||
if (name.endsWith("arm64_fixed_webview2-setup.nsis.zip.sig")) {
|
||||
const sig = await getSignature(browser_download_url);
|
||||
updateData.platforms["windows-aarch64"].signature = sig;
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.allSettled(promises);
|
||||
console.log(updateData);
|
||||
|
||||
// maybe should test the signature as well
|
||||
// delete the null field
|
||||
Object.entries(updateData.platforms).forEach(([key, value]) => {
|
||||
if (!value.url) {
|
||||
console.log(`[Error]: failed to parse release for "${key}"`);
|
||||
delete updateData.platforms[key];
|
||||
}
|
||||
});
|
||||
|
||||
// 生成一个代理github的更新文件
|
||||
// 使用 https://hub.fastgit.xyz/ 做github资源的加速
|
||||
const updateDataNew = JSON.parse(JSON.stringify(updateData));
|
||||
|
||||
Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
|
||||
if (value.url) {
|
||||
updateDataNew.platforms[key].url =
|
||||
"https://mirror.ghproxy.com/" + value.url;
|
||||
} else {
|
||||
console.log(`[Error]: updateDataNew.platforms.${key} is null`);
|
||||
}
|
||||
});
|
||||
|
||||
// update the update.json
|
||||
const { data: updateRelease } = await github.rest.repos.getReleaseByTag({
|
||||
...options,
|
||||
tag: UPDATE_TAG_NAME,
|
||||
});
|
||||
|
||||
// delete the old assets
|
||||
for (let asset of updateRelease.assets) {
|
||||
if (asset.name === UPDATE_JSON_FILE) {
|
||||
await github.rest.repos.deleteReleaseAsset({
|
||||
...options,
|
||||
asset_id: asset.id,
|
||||
});
|
||||
}
|
||||
|
||||
if (asset.name === UPDATE_JSON_PROXY) {
|
||||
await github.rest.repos
|
||||
.deleteReleaseAsset({ ...options, asset_id: asset.id })
|
||||
.catch(console.error); // do not break the pipeline
|
||||
}
|
||||
}
|
||||
|
||||
// upload new assets
|
||||
await github.rest.repos.uploadReleaseAsset({
|
||||
...options,
|
||||
release_id: updateRelease.id,
|
||||
name: UPDATE_JSON_FILE,
|
||||
data: JSON.stringify(updateData, null, 2),
|
||||
});
|
||||
|
||||
await github.rest.repos.uploadReleaseAsset({
|
||||
...options,
|
||||
release_id: updateRelease.id,
|
||||
name: UPDATE_JSON_PROXY,
|
||||
data: JSON.stringify(updateDataNew, null, 2),
|
||||
});
|
||||
}
|
||||
|
||||
// get the signature file content
|
||||
async function getSignature(url) {
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/octet-stream" },
|
||||
});
|
||||
|
||||
return response.text();
|
||||
}
|
||||
|
||||
resolveUpdater().catch(console.error);
|
||||
@@ -45,10 +45,14 @@ async function resolveUpdater() {
|
||||
"darwin-intel": { signature: "", url: "" },
|
||||
"darwin-x86_64": { signature: "", url: "" },
|
||||
"linux-x86_64": { signature: "", url: "" },
|
||||
"linux-x86": { signature: "", url: "" },
|
||||
"linux-i686": { signature: "", url: "" },
|
||||
"linux-aarch64": { signature: "", url: "" },
|
||||
"linux-armv7": { signature: "", url: "" },
|
||||
"windows-x86_64": { signature: "", url: "" },
|
||||
"windows-aarch64": { signature: "", url: "" },
|
||||
"windows-x86": { signature: "", url: "" },
|
||||
"windows-i686": { signature: "", url: "" },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -67,6 +71,18 @@ async function resolveUpdater() {
|
||||
updateData.platforms["windows-x86_64"].signature = sig;
|
||||
}
|
||||
|
||||
// win32 url
|
||||
if (name.endsWith("x64-setup.nsis.zip")) {
|
||||
updateData.platforms["windows-x86"].url = browser_download_url;
|
||||
updateData.platforms["windows-i686"].url = browser_download_url;
|
||||
}
|
||||
// win32 signature
|
||||
if (name.endsWith("x64-setup.nsis.zip.sig")) {
|
||||
const sig = await getSignature(browser_download_url);
|
||||
updateData.platforms["windows-x86"].signature = sig;
|
||||
updateData.platforms["windows-i686"].signature = sig;
|
||||
}
|
||||
|
||||
// win arm url
|
||||
if (name.endsWith("arm64-setup.nsis.zip")) {
|
||||
updateData.platforms["windows-aarch64"].url = browser_download_url;
|
||||
@@ -94,27 +110,22 @@ async function resolveUpdater() {
|
||||
// darwin url (aarch)
|
||||
if (name.endsWith("aarch64.app.tar.gz")) {
|
||||
updateData.platforms["darwin-aarch64"].url = browser_download_url;
|
||||
// 使linux可以检查更新
|
||||
updateData.platforms.linux.url = browser_download_url;
|
||||
updateData.platforms["linux-x86_64"].url = browser_download_url;
|
||||
updateData.platforms["linux-x86"].url = browser_download_url;
|
||||
updateData.platforms["linux-i686"].url = browser_download_url;
|
||||
updateData.platforms["linux-aarch64"].url = browser_download_url;
|
||||
updateData.platforms["linux-armv7"].url = browser_download_url;
|
||||
}
|
||||
// darwin signature (aarch)
|
||||
if (name.endsWith("aarch64.app.tar.gz.sig")) {
|
||||
const sig = await getSignature(browser_download_url);
|
||||
updateData.platforms["darwin-aarch64"].signature = sig;
|
||||
}
|
||||
|
||||
// linux x64 url
|
||||
if (name.endsWith("amd64.AppImage.tar.gz")) {
|
||||
updateData.platforms.linux.url = browser_download_url;
|
||||
updateData.platforms["linux-x86_64"].url = browser_download_url;
|
||||
// 暂时使用x64版本的url和sig,使得可以检查更新,但aarch64版本还不支持构建appimage
|
||||
updateData.platforms["linux-aarch64"].url = browser_download_url;
|
||||
updateData.platforms["linux-armv7"].url = browser_download_url;
|
||||
}
|
||||
// linux x64 signature
|
||||
if (name.endsWith("amd64.AppImage.tar.gz.sig")) {
|
||||
const sig = await getSignature(browser_download_url);
|
||||
updateData.platforms.linux.signature = sig;
|
||||
updateData.platforms["linux-x86_64"].signature = sig;
|
||||
// 暂时使用x64版本的url和sig,使得可以检查更新,但aarch64版本还不支持构建appimage
|
||||
updateData.platforms["linux-x86"].url = browser_download_url;
|
||||
updateData.platforms["linux-i686"].url = browser_download_url;
|
||||
updateData.platforms["linux-aarch64"].signature = sig;
|
||||
updateData.platforms["linux-armv7"].signature = sig;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "clash-verge"
|
||||
version = "1.5.10"
|
||||
version = "1.6.6"
|
||||
description = "clash verge"
|
||||
authors = ["zzzgydi", "wonfen", "MystiPanda"]
|
||||
license = "GPL-3.0-only"
|
||||
@@ -10,13 +10,13 @@ edition = "2021"
|
||||
build = "build.rs"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1", features = [] }
|
||||
tauri-build = { git="https://github.com/tauri-apps/tauri",branch = "1.x", features = [] }
|
||||
|
||||
[dependencies]
|
||||
warp = "0.3"
|
||||
anyhow = "1.0"
|
||||
dirs = "5.0"
|
||||
open = "5.0"
|
||||
open = "5.1"
|
||||
log = "0.4"
|
||||
dunce = "1.0"
|
||||
log4rs = "1"
|
||||
@@ -26,9 +26,9 @@ sysinfo = "0.30"
|
||||
boa_engine = "0.18"
|
||||
serde_json = "1.0"
|
||||
serde_yaml = "0.9"
|
||||
once_cell = "1.18"
|
||||
once_cell = "1.19"
|
||||
port_scanner = "0.1.5"
|
||||
delay_timer = "0.11.5"
|
||||
delay_timer = "0.11"
|
||||
parking_lot = "0.12"
|
||||
percent-encoding = "2.3.1"
|
||||
window-shadows = { version = "0.2" }
|
||||
@@ -37,14 +37,14 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
|
||||
sysproxy = { git="https://github.com/zzzgydi/sysproxy-rs", branch = "main" }
|
||||
auto-launch = { git="https://github.com/zzzgydi/auto-launch", branch = "main" }
|
||||
tauri = { version = "1.6", 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", "devtools"] }
|
||||
|
||||
tauri = { git="https://github.com/tauri-apps/tauri",branch = "1.x", features = [ "fs-read-file", "fs-exists", "path-all", "protocol-asset", "dialog-open", "notification-all", "icon-png", "icon-ico", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all", "devtools"] }
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
runas = "=1.2.0"
|
||||
deelevate = "0.2.0"
|
||||
winreg = "0.52.0"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
users = "0.11.0"
|
||||
#openssl
|
||||
|
||||
[features]
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -8,7 +8,7 @@ use crate::{ret_err, wrap_err};
|
||||
use anyhow::{Context, Result};
|
||||
use serde_yaml::Mapping;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use sysproxy::Sysproxy;
|
||||
use sysproxy::{Autoproxy, Sysproxy};
|
||||
use tauri::{api, Manager};
|
||||
type CmdResult<T = ()> = Result<T, String>;
|
||||
|
||||
@@ -65,6 +65,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult {
|
||||
match CoreManager::global().update_config().await {
|
||||
Ok(_) => {
|
||||
handle::Handle::refresh_clash();
|
||||
let _ = handle::Handle::update_systray_part();
|
||||
Config::profiles().apply();
|
||||
wrap_err!(Config::profiles().data().save_file())?;
|
||||
Ok(())
|
||||
@@ -193,7 +194,6 @@ pub fn grant_permission(_core: String) -> CmdResult {
|
||||
#[tauri::command]
|
||||
pub fn get_sys_proxy() -> CmdResult<Mapping> {
|
||||
let current = wrap_err!(Sysproxy::get_system_proxy())?;
|
||||
|
||||
let mut map = Mapping::new();
|
||||
map.insert("enable".into(), current.enable.into());
|
||||
map.insert(
|
||||
@@ -205,6 +205,18 @@ pub fn get_sys_proxy() -> CmdResult<Mapping> {
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
/// get the system proxy
|
||||
#[tauri::command]
|
||||
pub fn get_auto_proxy() -> CmdResult<Mapping> {
|
||||
let current = wrap_err!(Autoproxy::get_auto_proxy())?;
|
||||
|
||||
let mut map = Mapping::new();
|
||||
map.insert("enable".into(), current.enable.into());
|
||||
map.insert("url".into(), current.url.into());
|
||||
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_clash_logs() -> CmdResult<VecDeque<String>> {
|
||||
Ok(logger::Logger::global().get_log())
|
||||
@@ -299,15 +311,23 @@ pub fn copy_icon_file(path: String, name: String) -> CmdResult<String> {
|
||||
if !icon_dir.exists() {
|
||||
let _ = std::fs::create_dir_all(&icon_dir);
|
||||
}
|
||||
let dest_path = icon_dir.join(name);
|
||||
let ext = match file_path.extension() {
|
||||
Some(e) => e.to_string_lossy().to_string(),
|
||||
None => "ico".to_string(),
|
||||
};
|
||||
|
||||
let png_dest_path = icon_dir.join(format!("{name}.png"));
|
||||
let ico_dest_path = icon_dir.join(format!("{name}.ico"));
|
||||
let dest_path = icon_dir.join(format!("{name}.{ext}"));
|
||||
if file_path.exists() {
|
||||
std::fs::remove_file(png_dest_path).unwrap_or_default();
|
||||
std::fs::remove_file(ico_dest_path).unwrap_or_default();
|
||||
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());
|
||||
Err("file not found".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,42 +351,23 @@ pub fn exit_app(app_handle: tauri::AppHandle) {
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub mod service {
|
||||
use super::*;
|
||||
use crate::core::win_service;
|
||||
use crate::core::service;
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn check_service() -> CmdResult<win_service::JsonResponse> {
|
||||
wrap_err!(win_service::check_service().await)
|
||||
pub async fn check_service() -> CmdResult<service::JsonResponse> {
|
||||
wrap_err!(service::check_service().await)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_service() -> CmdResult {
|
||||
wrap_err!(win_service::install_service().await)
|
||||
wrap_err!(service::install_service().await)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn uninstall_service() -> CmdResult {
|
||||
wrap_err!(win_service::uninstall_service().await)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub mod service {
|
||||
use super::*;
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn check_service() -> CmdResult {
|
||||
Ok(())
|
||||
}
|
||||
#[tauri::command]
|
||||
pub async fn install_service() -> CmdResult {
|
||||
Ok(())
|
||||
}
|
||||
#[tauri::command]
|
||||
pub async fn uninstall_service() -> CmdResult {
|
||||
Ok(())
|
||||
wrap_err!(service::uninstall_service().await)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ impl IClashTemp {
|
||||
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());
|
||||
tun.insert("mtu".into(), 1500.into());
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
map.insert("redir-port".into(), 7895.into());
|
||||
#[cfg(target_os = "linux")]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
mod clash;
|
||||
#[allow(clippy::module_inception)]
|
||||
mod config;
|
||||
mod draft;
|
||||
mod prfitem;
|
||||
@@ -13,3 +14,8 @@ pub use self::prfitem::*;
|
||||
pub use self::profiles::*;
|
||||
pub use self::runtime::*;
|
||||
pub use self::verge::*;
|
||||
|
||||
pub const DEFAULT_PAC: &str = r#"function FindProxyForURL(url, host) {
|
||||
return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;";
|
||||
}
|
||||
"#;
|
||||
|
||||
@@ -46,6 +46,10 @@ pub struct PrfItem {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub option: Option<PrfOption>,
|
||||
|
||||
/// profile web page url
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub home: Option<String>,
|
||||
|
||||
/// the file data
|
||||
#[serde(skip)]
|
||||
pub file_data: Option<String>,
|
||||
@@ -99,7 +103,9 @@ impl PrfOption {
|
||||
a.user_agent = b.user_agent.or(a.user_agent);
|
||||
a.with_proxy = b.with_proxy.or(a.with_proxy);
|
||||
a.self_proxy = b.self_proxy.or(a.self_proxy);
|
||||
a.danger_accept_invalid_certs = b.danger_accept_invalid_certs.or(a.danger_accept_invalid_certs);
|
||||
a.danger_accept_invalid_certs = b
|
||||
.danger_accept_invalid_certs
|
||||
.or(a.danger_accept_invalid_certs);
|
||||
a.update_interval = b.update_interval.or(a.update_interval);
|
||||
Some(a)
|
||||
}
|
||||
@@ -161,6 +167,7 @@ impl PrfItem {
|
||||
selected: None,
|
||||
extra: None,
|
||||
option: None,
|
||||
home: None,
|
||||
updated: Some(chrono::Local::now().timestamp() as usize),
|
||||
file_data: Some(file_data.unwrap_or(tmpl::ITEM_LOCAL.into())),
|
||||
})
|
||||
@@ -177,7 +184,8 @@ impl PrfItem {
|
||||
let opt_ref = option.as_ref();
|
||||
let with_proxy = opt_ref.map_or(false, |o| o.with_proxy.unwrap_or(false));
|
||||
let self_proxy = opt_ref.map_or(false, |o| o.self_proxy.unwrap_or(false));
|
||||
let accept_invalid_certs = opt_ref.map_or(false, |o| o.danger_accept_invalid_certs.unwrap_or(false));
|
||||
let accept_invalid_certs =
|
||||
opt_ref.map_or(false, |o| o.danger_accept_invalid_certs.unwrap_or(false));
|
||||
let user_agent = opt_ref.and_then(|o| o.user_agent.clone());
|
||||
let update_interval = opt_ref.and_then(|o| o.update_interval);
|
||||
|
||||
@@ -291,6 +299,14 @@ impl PrfItem {
|
||||
},
|
||||
};
|
||||
|
||||
let home = match header.get("profile-web-page-url") {
|
||||
Some(value) => {
|
||||
let str_value = value.to_str().unwrap_or("");
|
||||
Some(str_value.to_string())
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let uid = help::get_uid("r");
|
||||
let file = format!("{uid}.yaml");
|
||||
let name = name.unwrap_or(filename.unwrap_or("Remote File".into()));
|
||||
@@ -317,6 +333,7 @@ impl PrfItem {
|
||||
selected: None,
|
||||
extra,
|
||||
option,
|
||||
home,
|
||||
updated: Some(chrono::Local::now().timestamp() as usize),
|
||||
file_data: Some(data.into()),
|
||||
})
|
||||
@@ -338,6 +355,7 @@ impl PrfItem {
|
||||
selected: None,
|
||||
extra: None,
|
||||
option: None,
|
||||
home: None,
|
||||
updated: Some(chrono::Local::now().timestamp() as usize),
|
||||
file_data: Some(tmpl::ITEM_MERGE.into()),
|
||||
})
|
||||
@@ -356,6 +374,7 @@ impl PrfItem {
|
||||
desc: Some(desc),
|
||||
file: Some(file),
|
||||
url: None,
|
||||
home: None,
|
||||
selected: None,
|
||||
extra: None,
|
||||
option: None,
|
||||
|
||||
@@ -211,7 +211,7 @@ impl IProfiles {
|
||||
if each.uid == some_uid {
|
||||
each.extra = item.extra;
|
||||
each.updated = item.updated;
|
||||
|
||||
each.home = item.home;
|
||||
// save the file data
|
||||
// move the field value after save
|
||||
if let Some(file_data) = item.file_data.take() {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::config::DEFAULT_PAC;
|
||||
use crate::utils::{dirs, help};
|
||||
use anyhow::Result;
|
||||
use log::LevelFilter;
|
||||
@@ -42,6 +43,10 @@ pub struct IVerge {
|
||||
/// common tray icon
|
||||
pub common_tray_icon: Option<bool>,
|
||||
|
||||
/// tray icon
|
||||
#[cfg(target_os = "macos")]
|
||||
pub tray_icon: Option<String>,
|
||||
|
||||
/// menu icon
|
||||
pub menu_icon: Option<String>,
|
||||
|
||||
@@ -76,6 +81,12 @@ pub struct IVerge {
|
||||
/// proxy guard duration
|
||||
pub proxy_guard_duration: Option<u64>,
|
||||
|
||||
/// use pac mode
|
||||
pub proxy_auto_config: Option<bool>,
|
||||
|
||||
/// pac script content
|
||||
pub pac_file_content: Option<String>,
|
||||
|
||||
/// theme setting
|
||||
pub theme_setting: Option<IVergeTheme>,
|
||||
|
||||
@@ -130,14 +141,24 @@ pub struct IVerge {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub verge_redir_port: Option<u16>,
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub verge_redir_enabled: Option<bool>,
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub verge_tproxy_port: Option<u16>,
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub verge_tproxy_enabled: Option<bool>,
|
||||
|
||||
pub verge_mixed_port: Option<u16>,
|
||||
|
||||
pub verge_socks_port: Option<u16>,
|
||||
|
||||
pub verge_socks_enabled: Option<bool>,
|
||||
|
||||
pub verge_port: Option<u16>,
|
||||
|
||||
pub verge_http_enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
||||
@@ -188,6 +209,8 @@ impl IVerge {
|
||||
traffic_graph: Some(true),
|
||||
enable_memory_usage: Some(true),
|
||||
enable_group_icon: Some(true),
|
||||
#[cfg(target_os = "macos")]
|
||||
tray_icon: Some("monochrome".into()),
|
||||
menu_icon: Some("monochrome".into()),
|
||||
common_tray_icon: Some(false),
|
||||
sysproxy_tray_icon: Some(false),
|
||||
@@ -195,14 +218,22 @@ impl IVerge {
|
||||
enable_auto_launch: Some(false),
|
||||
enable_silent_start: Some(false),
|
||||
enable_system_proxy: Some(false),
|
||||
proxy_auto_config: Some(false),
|
||||
pac_file_content: Some(DEFAULT_PAC.into()),
|
||||
enable_random_port: Some(false),
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
verge_redir_port: Some(7895),
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
verge_redir_enabled: Some(true),
|
||||
#[cfg(target_os = "linux")]
|
||||
verge_tproxy_port: Some(7896),
|
||||
#[cfg(target_os = "linux")]
|
||||
verge_tproxy_enabled: Some(true),
|
||||
verge_mixed_port: Some(7897),
|
||||
verge_socks_port: Some(7898),
|
||||
verge_socks_enabled: Some(true),
|
||||
verge_port: Some(7899),
|
||||
verge_http_enabled: Some(true),
|
||||
enable_proxy_guard: Some(false),
|
||||
proxy_guard_duration: Some(30),
|
||||
auto_close_connection: Some(true),
|
||||
@@ -239,6 +270,8 @@ impl IVerge {
|
||||
patch!(traffic_graph);
|
||||
patch!(enable_memory_usage);
|
||||
patch!(enable_group_icon);
|
||||
#[cfg(target_os = "macos")]
|
||||
patch!(tray_icon);
|
||||
patch!(menu_icon);
|
||||
patch!(common_tray_icon);
|
||||
patch!(sysproxy_tray_icon);
|
||||
@@ -251,15 +284,23 @@ impl IVerge {
|
||||
patch!(enable_random_port);
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
patch!(verge_redir_port);
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
patch!(verge_redir_enabled);
|
||||
#[cfg(target_os = "linux")]
|
||||
patch!(verge_tproxy_port);
|
||||
#[cfg(target_os = "linux")]
|
||||
patch!(verge_tproxy_enabled);
|
||||
patch!(verge_mixed_port);
|
||||
patch!(verge_socks_port);
|
||||
patch!(verge_socks_enabled);
|
||||
patch!(verge_port);
|
||||
patch!(verge_http_enabled);
|
||||
patch!(enable_system_proxy);
|
||||
patch!(enable_proxy_guard);
|
||||
patch!(system_proxy_bypass);
|
||||
patch!(proxy_guard_duration);
|
||||
patch!(proxy_auto_config);
|
||||
patch!(pac_file_content);
|
||||
|
||||
patch!(theme_setting);
|
||||
patch!(web_ui_list);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use super::service;
|
||||
use super::{clash_api, logger::Logger};
|
||||
use crate::log_err;
|
||||
use crate::{config::*, utils::dirs};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use serde_yaml::Mapping;
|
||||
use std::{fs, io::Write, sync::Arc, time::Duration};
|
||||
use sysinfo::{Pid, System};
|
||||
use tauri::api::process::{Command, CommandChild, CommandEvent};
|
||||
@@ -93,10 +95,9 @@ impl CoreManager {
|
||||
None => false,
|
||||
};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
if *self.use_service_mode.lock() {
|
||||
log::debug!(target: "app", "stop the core by service");
|
||||
log_err!(super::win_service::stop_core_by_service().await);
|
||||
log_err!(service::stop_core_by_service().await);
|
||||
should_kill = true;
|
||||
}
|
||||
|
||||
@@ -105,32 +106,27 @@ impl CoreManager {
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use super::win_service;
|
||||
// 服务模式
|
||||
let enable = { Config::verge().latest().enable_service_mode };
|
||||
let enable = enable.unwrap_or(false);
|
||||
|
||||
// 服务模式
|
||||
let enable = { Config::verge().latest().enable_service_mode };
|
||||
let enable = enable.unwrap_or(false);
|
||||
*self.use_service_mode.lock() = enable;
|
||||
|
||||
*self.use_service_mode.lock() = enable;
|
||||
if enable {
|
||||
// 服务模式启动失败就直接运行sidecar
|
||||
log::debug!(target: "app", "try to run core in service mode");
|
||||
|
||||
if enable {
|
||||
// 服务模式启动失败就直接运行sidecar
|
||||
log::debug!(target: "app", "try to run core in service mode");
|
||||
|
||||
match (|| async {
|
||||
win_service::check_service().await?;
|
||||
win_service::run_core_by_service(&config_path).await
|
||||
})()
|
||||
.await
|
||||
{
|
||||
Ok(_) => return Ok(()),
|
||||
Err(err) => {
|
||||
// 修改这个值,免得stop出错
|
||||
*self.use_service_mode.lock() = false;
|
||||
log::error!(target: "app", "{err}");
|
||||
}
|
||||
let res = async {
|
||||
service::check_service().await?;
|
||||
service::run_core_by_service(&config_path).await
|
||||
}
|
||||
.await;
|
||||
match res {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(err) => {
|
||||
// 修改这个值,免得stop出错
|
||||
*self.use_service_mode.lock() = false;
|
||||
log::error!(target: "app", "{err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -205,7 +201,6 @@ impl CoreManager {
|
||||
/// 重启内核
|
||||
pub fn recover_core(&'static self) -> Result<()> {
|
||||
// 服务模式不管
|
||||
#[cfg(target_os = "windows")]
|
||||
if *self.use_service_mode.lock() {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -238,11 +233,20 @@ impl CoreManager {
|
||||
|
||||
/// 停止核心运行
|
||||
pub fn stop_core(&self) -> Result<()> {
|
||||
#[cfg(target_os = "windows")]
|
||||
// 关闭tun模式
|
||||
tauri::async_runtime::block_on(async move {
|
||||
let mut disable = Mapping::new();
|
||||
let mut tun = Mapping::new();
|
||||
tun.insert("enable".into(), false.into());
|
||||
disable.insert("tun".into(), tun.into());
|
||||
log::debug!(target: "app", "disable tun mode");
|
||||
let _ = clash_api::patch_configs(&disable).await;
|
||||
});
|
||||
|
||||
if *self.use_service_mode.lock() {
|
||||
log::debug!(target: "app", "stop the core by service");
|
||||
tauri::async_runtime::block_on(async move {
|
||||
log_err!(super::win_service::stop_core_by_service().await);
|
||||
log_err!(service::stop_core_by_service().await);
|
||||
});
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ impl Hotkey {
|
||||
}
|
||||
}
|
||||
}
|
||||
*self.current.lock() = hotkeys.clone();
|
||||
self.current.lock().clone_from(hotkeys);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -142,7 +142,7 @@ impl Hotkey {
|
||||
});
|
||||
|
||||
new_map.iter().for_each(|(&key, &func)| {
|
||||
if old_map.get(key).is_none() {
|
||||
if !old_map.contains_key(key) {
|
||||
add_list.push((key, func));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -22,7 +22,8 @@ pub fn grant_permission(core: String) -> anyhow::Result<()> {
|
||||
#[cfg(target_os = "linux")]
|
||||
let output = {
|
||||
let path = path.replace(' ', "\\ "); // 避免路径中有空格
|
||||
let shell = format!("setcap cap_net_bind_service,cap_net_admin=+ep {path}");
|
||||
let shell =
|
||||
format!("setcap cap_net_bind_service,cap_net_admin,cap_dac_override=+ep {path}");
|
||||
|
||||
let sudo = match Command::new("which").arg("pkexec").output() {
|
||||
Ok(output) => {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
pub mod clash_api;
|
||||
#[allow(clippy::module_inception)]
|
||||
mod core;
|
||||
pub mod handle;
|
||||
pub mod hotkey;
|
||||
pub mod logger;
|
||||
pub mod manager;
|
||||
pub mod service;
|
||||
pub mod sysopt;
|
||||
pub mod timer;
|
||||
pub mod tray;
|
||||
pub mod win_service;
|
||||
pub mod win_uwp;
|
||||
|
||||
pub use self::core::*;
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
#![cfg(target_os = "windows")]
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::utils::dirs;
|
||||
use anyhow::{bail, Context, Result};
|
||||
use deelevate::{PrivilegeLevel, Token};
|
||||
use runas::Command as RunasCommand;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::os::windows::process::CommandExt;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use std::{env::current_exe, process::Command as StdCommand};
|
||||
use tokio::time::sleep;
|
||||
|
||||
// Windows only
|
||||
|
||||
const SERVICE_URL: &str = "http://127.0.0.1:33211";
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
@@ -32,7 +29,13 @@ pub struct JsonResponse {
|
||||
|
||||
/// Install the Clash Verge Service
|
||||
/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
|
||||
///
|
||||
#[cfg(target_os = "windows")]
|
||||
pub async fn install_service() -> Result<()> {
|
||||
use deelevate::{PrivilegeLevel, Token};
|
||||
use runas::Command as RunasCommand;
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
let binary_path = dirs::service_path()?;
|
||||
let install_path = binary_path.with_file_name("install-service.exe");
|
||||
|
||||
@@ -60,9 +63,69 @@ pub async fn install_service() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub async fn install_service() -> Result<()> {
|
||||
use users::get_effective_uid;
|
||||
|
||||
let binary_path = dirs::service_path()?;
|
||||
let installer_path = binary_path.with_file_name("install-service");
|
||||
|
||||
if !installer_path.exists() {
|
||||
bail!("installer not found");
|
||||
}
|
||||
|
||||
let elevator = crate::utils::unix_helper::linux_elevator();
|
||||
let status = match get_effective_uid() {
|
||||
0 => StdCommand::new(installer_path).status()?,
|
||||
_ => StdCommand::new(elevator)
|
||||
.arg("sh")
|
||||
.arg("-c")
|
||||
.arg(installer_path)
|
||||
.status()?,
|
||||
};
|
||||
|
||||
if !status.success() {
|
||||
bail!(
|
||||
"failed to install service with status {}",
|
||||
status.code().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub async fn install_service() -> Result<()> {
|
||||
let binary_path = dirs::service_path()?;
|
||||
let installer_path = binary_path.with_file_name("install-service");
|
||||
|
||||
if !installer_path.exists() {
|
||||
bail!("installer not found");
|
||||
}
|
||||
let shell = installer_path.to_string_lossy().replace(" ", "\\\\ ");
|
||||
let command = format!(r#"do shell script "{shell}" with administrator privileges"#);
|
||||
|
||||
let status = StdCommand::new("osascript")
|
||||
.args(vec!["-e", &command])
|
||||
.status()?;
|
||||
|
||||
if !status.success() {
|
||||
bail!(
|
||||
"failed to install service with status {}",
|
||||
status.code().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
/// Uninstall the Clash Verge Service
|
||||
/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
|
||||
#[cfg(target_os = "windows")]
|
||||
pub async fn uninstall_service() -> Result<()> {
|
||||
use deelevate::{PrivilegeLevel, Token};
|
||||
use runas::Command as RunasCommand;
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
let binary_path = dirs::service_path()?;
|
||||
let uninstall_path = binary_path.with_file_name("uninstall-service.exe");
|
||||
|
||||
@@ -90,6 +153,63 @@ pub async fn uninstall_service() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub async fn uninstall_service() -> Result<()> {
|
||||
use users::get_effective_uid;
|
||||
|
||||
let binary_path = dirs::service_path()?;
|
||||
let uninstaller_path = binary_path.with_file_name("uninstall-service");
|
||||
|
||||
if !uninstaller_path.exists() {
|
||||
bail!("uninstaller not found");
|
||||
}
|
||||
|
||||
let elevator = crate::utils::unix_helper::linux_elevator();
|
||||
let status = match get_effective_uid() {
|
||||
0 => StdCommand::new(uninstaller_path).status()?,
|
||||
_ => StdCommand::new(elevator)
|
||||
.arg("sh")
|
||||
.arg("-c")
|
||||
.arg(uninstaller_path)
|
||||
.status()?,
|
||||
};
|
||||
|
||||
if !status.success() {
|
||||
bail!(
|
||||
"failed to install service with status {}",
|
||||
status.code().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub async fn uninstall_service() -> Result<()> {
|
||||
let binary_path = dirs::service_path()?;
|
||||
let uninstaller_path = binary_path.with_file_name("uninstall-service");
|
||||
|
||||
if !uninstaller_path.exists() {
|
||||
bail!("uninstaller not found");
|
||||
}
|
||||
|
||||
let shell = uninstaller_path.to_string_lossy().replace(" ", "\\\\ ");
|
||||
let command = format!(r#"do shell script "{shell}" with administrator privileges"#);
|
||||
|
||||
let status = StdCommand::new("osascript")
|
||||
.args(vec!["-e", &command])
|
||||
.status()?;
|
||||
|
||||
if !status.success() {
|
||||
bail!(
|
||||
"failed to install service with status {}",
|
||||
status.code().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// check the windows service status
|
||||
pub async fn check_service() -> Result<JsonResponse> {
|
||||
let url = format!("{SERVICE_URL}/get_clash");
|
||||
@@ -119,7 +239,8 @@ pub(super) async fn run_core_by_service(config_file: &PathBuf) -> Result<()> {
|
||||
let clash_core = { Config::verge().latest().clash_core.clone() };
|
||||
let clash_core = clash_core.unwrap_or("clash".into());
|
||||
|
||||
let clash_bin = format!("{clash_core}.exe");
|
||||
let bin_ext = if cfg!(windows) { ".exe" } else { "" };
|
||||
let clash_bin = format!("{clash_core}{bin_ext}");
|
||||
let bin_path = current_exe()?.with_file_name(clash_bin);
|
||||
let bin_path = dirs::path_to_str(&bin_path)?;
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
use crate::{config::Config, log_err};
|
||||
use crate::{
|
||||
config::{Config, IVerge},
|
||||
log_err,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use auto_launch::{AutoLaunch, AutoLaunchBuilder};
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use std::env::current_exe;
|
||||
use std::sync::Arc;
|
||||
use sysproxy::Sysproxy;
|
||||
use tauri::{async_runtime::Mutex as TokioMutex, utils::platform::current_exe};
|
||||
use sysproxy::{Autoproxy, Sysproxy};
|
||||
use tauri::async_runtime::Mutex as TokioMutex;
|
||||
|
||||
pub struct Sysopt {
|
||||
/// current system proxy setting
|
||||
@@ -15,6 +19,13 @@ pub struct Sysopt {
|
||||
/// recover it when exit
|
||||
old_sysproxy: Arc<Mutex<Option<Sysproxy>>>,
|
||||
|
||||
/// current auto proxy setting
|
||||
cur_autoproxy: Arc<Mutex<Option<Autoproxy>>>,
|
||||
|
||||
/// record the original auto proxy
|
||||
/// recover it when exit
|
||||
old_autoproxy: Arc<Mutex<Option<Autoproxy>>>,
|
||||
|
||||
/// helps to auto launch the app
|
||||
auto_launch: Arc<Mutex<Option<AutoLaunch>>>,
|
||||
|
||||
@@ -23,13 +34,41 @@ pub struct Sysopt {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
static DEFAULT_BYPASS: &str = "localhost;127.*;192.168.*;10.*;172.16.*;<local>";
|
||||
static DEFAULT_BYPASS: &str = "localhost;127.*;192.168.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;<local>";
|
||||
#[cfg(target_os = "linux")]
|
||||
static DEFAULT_BYPASS: &str = "localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,::1";
|
||||
#[cfg(target_os = "macos")]
|
||||
static DEFAULT_BYPASS: &str =
|
||||
"127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,localhost,*.local,*.crashlytics.com,<local>";
|
||||
|
||||
fn get_bypass() -> String {
|
||||
let bypass = DEFAULT_BYPASS.to_string();
|
||||
|
||||
let res = {
|
||||
let verge = Config::verge();
|
||||
let verge = verge.latest();
|
||||
verge.system_proxy_bypass.clone()
|
||||
};
|
||||
let custom_bypass = match res {
|
||||
Some(bypass) => bypass,
|
||||
None => "".to_string(),
|
||||
};
|
||||
#[cfg(target_os = "windows")]
|
||||
let bypass = if custom_bypass.is_empty() {
|
||||
bypass
|
||||
} else {
|
||||
format!("{};{}", bypass, custom_bypass)
|
||||
};
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let bypass = if custom_bypass.is_empty() {
|
||||
bypass
|
||||
} else {
|
||||
format!("{},{}", bypass, custom_bypass)
|
||||
};
|
||||
|
||||
bypass
|
||||
}
|
||||
|
||||
impl Sysopt {
|
||||
pub fn global() -> &'static Sysopt {
|
||||
static SYSOPT: OnceCell<Sysopt> = OnceCell::new();
|
||||
@@ -37,6 +76,8 @@ impl Sysopt {
|
||||
SYSOPT.get_or_init(|| Sysopt {
|
||||
cur_sysproxy: Arc::new(Mutex::new(None)),
|
||||
old_sysproxy: Arc::new(Mutex::new(None)),
|
||||
cur_autoproxy: Arc::new(Mutex::new(None)),
|
||||
old_autoproxy: Arc::new(Mutex::new(None)),
|
||||
auto_launch: Arc::new(Mutex::new(None)),
|
||||
guard_state: Arc::new(TokioMutex::new(false)),
|
||||
})
|
||||
@@ -48,29 +89,48 @@ impl Sysopt {
|
||||
.latest()
|
||||
.verge_mixed_port
|
||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||
let pac_port = IVerge::get_singleton_port();
|
||||
|
||||
let (enable, bypass) = {
|
||||
let (enable, pac) = {
|
||||
let verge = Config::verge();
|
||||
let verge = verge.latest();
|
||||
(
|
||||
verge.enable_system_proxy.unwrap_or(false),
|
||||
verge.system_proxy_bypass.clone(),
|
||||
verge.proxy_auto_config.unwrap_or(false),
|
||||
)
|
||||
};
|
||||
|
||||
let current = Sysproxy {
|
||||
let mut sys = Sysproxy {
|
||||
enable,
|
||||
host: String::from("127.0.0.1"),
|
||||
port,
|
||||
bypass: bypass.unwrap_or(DEFAULT_BYPASS.into()),
|
||||
bypass: get_bypass(),
|
||||
};
|
||||
|
||||
if enable {
|
||||
let mut auto = Autoproxy {
|
||||
enable,
|
||||
url: format!("http://127.0.0.1:{pac_port}/commands/pac"),
|
||||
};
|
||||
if pac {
|
||||
sys.enable = false;
|
||||
let old = Sysproxy::get_system_proxy().ok();
|
||||
current.set_system_proxy()?;
|
||||
|
||||
sys.set_system_proxy()?;
|
||||
*self.old_sysproxy.lock() = old;
|
||||
*self.cur_sysproxy.lock() = Some(current);
|
||||
*self.cur_sysproxy.lock() = Some(sys);
|
||||
|
||||
let old = Autoproxy::get_auto_proxy().ok();
|
||||
auto.set_auto_proxy()?;
|
||||
*self.old_autoproxy.lock() = old;
|
||||
*self.cur_autoproxy.lock() = Some(auto);
|
||||
} else {
|
||||
auto.enable = false;
|
||||
let old = Autoproxy::get_auto_proxy().ok();
|
||||
auto.set_auto_proxy()?;
|
||||
*self.old_autoproxy.lock() = old;
|
||||
*self.cur_autoproxy.lock() = Some(auto);
|
||||
|
||||
let old = Sysproxy::get_system_proxy().ok();
|
||||
sys.set_system_proxy()?;
|
||||
*self.old_sysproxy.lock() = old;
|
||||
*self.cur_sysproxy.lock() = Some(sys);
|
||||
}
|
||||
|
||||
// run the system proxy guard
|
||||
@@ -82,34 +142,57 @@ impl Sysopt {
|
||||
pub fn update_sysproxy(&self) -> Result<()> {
|
||||
let mut cur_sysproxy = self.cur_sysproxy.lock();
|
||||
let old_sysproxy = self.old_sysproxy.lock();
|
||||
let mut cur_autoproxy = self.cur_autoproxy.lock();
|
||||
let old_autoproxy = self.old_autoproxy.lock();
|
||||
|
||||
if cur_sysproxy.is_none() || old_sysproxy.is_none() {
|
||||
let (enable, pac) = {
|
||||
let verge = Config::verge();
|
||||
let verge = verge.latest();
|
||||
(
|
||||
verge.enable_system_proxy.unwrap_or(false),
|
||||
verge.proxy_auto_config.unwrap_or(false),
|
||||
)
|
||||
};
|
||||
if pac && (cur_autoproxy.is_none() || old_autoproxy.is_none()) {
|
||||
drop(cur_autoproxy);
|
||||
drop(old_autoproxy);
|
||||
return self.init_sysproxy();
|
||||
}
|
||||
|
||||
if !pac && (cur_sysproxy.is_none() || old_sysproxy.is_none()) {
|
||||
drop(cur_sysproxy);
|
||||
drop(old_sysproxy);
|
||||
return self.init_sysproxy();
|
||||
}
|
||||
|
||||
let (enable, bypass) = {
|
||||
let verge = Config::verge();
|
||||
let verge = verge.latest();
|
||||
(
|
||||
verge.enable_system_proxy.unwrap_or(false),
|
||||
verge.system_proxy_bypass.clone(),
|
||||
)
|
||||
};
|
||||
let mut sysproxy = cur_sysproxy.take().unwrap();
|
||||
|
||||
sysproxy.enable = enable;
|
||||
sysproxy.bypass = bypass.unwrap_or(DEFAULT_BYPASS.into());
|
||||
|
||||
let port = Config::verge()
|
||||
.latest()
|
||||
.verge_mixed_port
|
||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||
let pac_port = IVerge::get_singleton_port();
|
||||
|
||||
let mut sysproxy = cur_sysproxy.take().unwrap();
|
||||
sysproxy.bypass = get_bypass();
|
||||
sysproxy.port = port;
|
||||
|
||||
sysproxy.set_system_proxy()?;
|
||||
*cur_sysproxy = Some(sysproxy);
|
||||
let mut autoproxy = cur_autoproxy.take().unwrap();
|
||||
autoproxy.url = format!("http://127.0.0.1:{pac_port}/commands/pac");
|
||||
|
||||
if pac {
|
||||
sysproxy.enable = false;
|
||||
sysproxy.set_system_proxy()?;
|
||||
*cur_sysproxy = Some(sysproxy);
|
||||
autoproxy.enable = enable;
|
||||
autoproxy.set_auto_proxy()?;
|
||||
*cur_autoproxy = Some(autoproxy);
|
||||
} else {
|
||||
autoproxy.enable = false;
|
||||
autoproxy.set_auto_proxy()?;
|
||||
*cur_autoproxy = Some(autoproxy);
|
||||
sysproxy.enable = enable;
|
||||
sysproxy.set_system_proxy()?;
|
||||
*cur_sysproxy = Some(sysproxy);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -118,8 +201,11 @@ impl Sysopt {
|
||||
pub fn reset_sysproxy(&self) -> Result<()> {
|
||||
let mut cur_sysproxy = self.cur_sysproxy.lock();
|
||||
let mut old_sysproxy = self.old_sysproxy.lock();
|
||||
let mut cur_autoproxy = self.cur_autoproxy.lock();
|
||||
let mut old_autoproxy = self.old_autoproxy.lock();
|
||||
|
||||
let cur_sysproxy = cur_sysproxy.take();
|
||||
let cur_autoproxy = cur_autoproxy.take();
|
||||
|
||||
if let Some(mut old) = old_sysproxy.take() {
|
||||
// 如果原代理和当前代理 端口一致,就disable关闭,否则就恢复原代理设置
|
||||
@@ -143,13 +229,35 @@ impl Sysopt {
|
||||
log::info!(target: "app", "reset proxy with no action");
|
||||
}
|
||||
|
||||
if let Some(mut old) = old_autoproxy.take() {
|
||||
// 如果原代理和当前代理 URL一致,就disable关闭,否则就恢复原代理设置
|
||||
// 当前没有设置代理的时候,不确定旧设置是否和当前一致,全关了
|
||||
let url_same = cur_autoproxy.map_or(true, |cur| old.url == cur.url);
|
||||
|
||||
if old.enable && url_same {
|
||||
old.enable = false;
|
||||
log::info!(target: "app", "reset proxy by disabling the original proxy");
|
||||
} else {
|
||||
log::info!(target: "app", "reset proxy to the original proxy");
|
||||
}
|
||||
|
||||
old.set_auto_proxy()?;
|
||||
} else if let Some(mut cur @ Autoproxy { enable: true, .. }) = cur_autoproxy {
|
||||
// 没有原代理,就按现在的代理设置disable即可
|
||||
log::info!(target: "app", "reset proxy by disabling the current proxy");
|
||||
cur.enable = false;
|
||||
cur.set_auto_proxy()?;
|
||||
} else {
|
||||
log::info!(target: "app", "reset proxy with no action");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// init the auto launch
|
||||
pub fn init_launch(&self) -> Result<()> {
|
||||
let app_exe = current_exe()?;
|
||||
let app_exe = dunce::canonicalize(app_exe)?;
|
||||
// let app_exe = dunce::canonicalize(app_exe)?;
|
||||
let app_name = app_exe
|
||||
.file_stem()
|
||||
.and_then(|f| f.to_str())
|
||||
@@ -248,14 +356,14 @@ impl Sysopt {
|
||||
loop {
|
||||
sleep(Duration::from_secs(wait_secs)).await;
|
||||
|
||||
let (enable, guard, guard_duration, bypass) = {
|
||||
let (enable, guard, guard_duration, pac) = {
|
||||
let verge = Config::verge();
|
||||
let verge = verge.latest();
|
||||
(
|
||||
verge.enable_system_proxy.unwrap_or(false),
|
||||
verge.enable_proxy_guard.unwrap_or(false),
|
||||
verge.proxy_guard_duration.unwrap_or(10),
|
||||
verge.system_proxy_bypass.clone(),
|
||||
verge.proxy_auto_config.unwrap_or(false),
|
||||
)
|
||||
};
|
||||
|
||||
@@ -275,15 +383,23 @@ impl Sysopt {
|
||||
.verge_mixed_port
|
||||
.unwrap_or(Config::clash().data().get_mixed_port())
|
||||
};
|
||||
let pac_port = IVerge::get_singleton_port();
|
||||
if pac {
|
||||
let autoproxy = Autoproxy {
|
||||
enable: true,
|
||||
url: format!("http://127.0.0.1:{pac_port}/commands/pac"),
|
||||
};
|
||||
log_err!(autoproxy.set_auto_proxy());
|
||||
} else {
|
||||
let sysproxy = Sysproxy {
|
||||
enable: true,
|
||||
host: "127.0.0.1".into(),
|
||||
port,
|
||||
bypass: get_bypass(),
|
||||
};
|
||||
|
||||
let sysproxy = Sysproxy {
|
||||
enable: true,
|
||||
host: "127.0.0.1".into(),
|
||||
port,
|
||||
bypass: bypass.unwrap_or(DEFAULT_BYPASS.into()),
|
||||
};
|
||||
|
||||
log_err!(sysproxy.set_system_proxy());
|
||||
log_err!(sysproxy.set_system_proxy());
|
||||
}
|
||||
}
|
||||
|
||||
let mut state = guard_state.lock().await;
|
||||
|
||||
@@ -88,7 +88,7 @@ impl Tray {
|
||||
),
|
||||
))
|
||||
.add_native_item(SystemTrayMenuItem::Separator)
|
||||
.add_item(CustomMenuItem::new("quit", t!("Quit", "退出")).accelerator("CmdOrControl+Q"))
|
||||
.add_item(CustomMenuItem::new("quit", t!("Quit", "退出")))
|
||||
}
|
||||
|
||||
pub fn update_systray(app_handle: &AppHandle) -> Result<()> {
|
||||
@@ -172,45 +172,81 @@ 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);
|
||||
#[cfg(target_os = "macos")]
|
||||
let tray_icon = verge.tray_icon.clone().unwrap_or("monochrome".to_string());
|
||||
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);
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
match tray_icon.as_str() {
|
||||
"monochrome" => {
|
||||
let _ = tray.set_icon_as_template(true);
|
||||
}
|
||||
"colorful" => {
|
||||
let _ = tray.set_icon_as_template(false);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut indication_icon = if *system_proxy {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let mut icon = include_bytes!("../../icons/tray-icon-sys.png").to_vec();
|
||||
#[cfg(target_os = "macos")]
|
||||
let mut icon = include_bytes!("../../icons/mac-tray-icon-sys.png").to_vec();
|
||||
let mut icon = match tray_icon.as_str() {
|
||||
"monochrome" => include_bytes!("../../icons/tray-icon-sys-mono.ico").to_vec(),
|
||||
"colorful" => include_bytes!("../../icons/tray-icon-sys.ico").to_vec(),
|
||||
_ => include_bytes!("../../icons/tray-icon-sys-mono.ico").to_vec(),
|
||||
};
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let mut icon = include_bytes!("../../icons/tray-icon-sys.ico").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();
|
||||
let icon_dir_path = dirs::app_home_dir()?.join("icons");
|
||||
let png_path = icon_dir_path.join("sysproxy.png");
|
||||
let ico_path = icon_dir_path.join("sysproxy.ico");
|
||||
if ico_path.exists() {
|
||||
icon = std::fs::read(ico_path).unwrap();
|
||||
} else if png_path.exists() {
|
||||
icon = std::fs::read(png_path).unwrap();
|
||||
}
|
||||
}
|
||||
icon
|
||||
} else {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let mut icon = include_bytes!("../../icons/tray-icon.png").to_vec();
|
||||
#[cfg(target_os = "macos")]
|
||||
let mut icon = include_bytes!("../../icons/mac-tray-icon.png").to_vec();
|
||||
let mut icon = match tray_icon.as_str() {
|
||||
"monochrome" => include_bytes!("../../icons/tray-icon-mono.ico").to_vec(),
|
||||
"colorful" => include_bytes!("../../icons/tray-icon.ico").to_vec(),
|
||||
_ => include_bytes!("../../icons/tray-icon-mono.ico").to_vec(),
|
||||
};
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let mut icon = include_bytes!("../../icons/tray-icon.ico").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();
|
||||
let icon_dir_path = dirs::app_home_dir()?.join("icons");
|
||||
let png_path = icon_dir_path.join("common.png");
|
||||
let ico_path = icon_dir_path.join("common.ico");
|
||||
if ico_path.exists() {
|
||||
icon = std::fs::read(ico_path).unwrap();
|
||||
} else if png_path.exists() {
|
||||
icon = std::fs::read(png_path).unwrap();
|
||||
}
|
||||
}
|
||||
icon
|
||||
};
|
||||
|
||||
if *tun_mode {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let mut icon = include_bytes!("../../icons/tray-icon-tun.png").to_vec();
|
||||
#[cfg(target_os = "macos")]
|
||||
let mut icon = include_bytes!("../../icons/mac-tray-icon-tun.png").to_vec();
|
||||
let mut icon = match tray_icon.as_str() {
|
||||
"monochrome" => include_bytes!("../../icons/tray-icon-tun-mono.ico").to_vec(),
|
||||
"colorful" => include_bytes!("../../icons/tray-icon-tun.ico").to_vec(),
|
||||
_ => include_bytes!("../../icons/tray-icon-tun-mono.ico").to_vec(),
|
||||
};
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let mut icon = include_bytes!("../../icons/tray-icon-tun.ico").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();
|
||||
let icon_dir_path = dirs::app_home_dir()?.join("icons");
|
||||
let png_path = icon_dir_path.join("tun.png");
|
||||
let ico_path = icon_dir_path.join("tun.ico");
|
||||
if ico_path.exists() {
|
||||
icon = std::fs::read(ico_path).unwrap();
|
||||
} else if png_path.exists() {
|
||||
icon = std::fs::read(png_path).unwrap();
|
||||
}
|
||||
}
|
||||
indication_icon = icon
|
||||
@@ -249,18 +285,30 @@ impl Tray {
|
||||
map
|
||||
};
|
||||
|
||||
let mut current_profile_name = "None".to_string();
|
||||
let profiles = Config::profiles();
|
||||
let profiles = profiles.latest();
|
||||
if let Some(current_profile_uid) = profiles.get_current() {
|
||||
let current_profile = profiles.get_item(¤t_profile_uid);
|
||||
current_profile_name = match ¤t_profile.unwrap().name {
|
||||
Some(profile_name) => profile_name.to_string(),
|
||||
None => current_profile_name,
|
||||
};
|
||||
};
|
||||
let _ = tray.set_tooltip(&format!(
|
||||
"Clash Verge {version}\n{}: {}\n{}: {}",
|
||||
"Clash Verge {version}\n{}: {}\n{}: {}\n{}: {}",
|
||||
t!("System Proxy", "系统代理"),
|
||||
switch_map[system_proxy],
|
||||
t!("TUN Mode", "Tun 模式"),
|
||||
switch_map[tun_mode]
|
||||
switch_map[tun_mode],
|
||||
t!("Curent Profile", "当前订阅"),
|
||||
current_profile_name
|
||||
));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn on_left_click(app_handle: &AppHandle) {
|
||||
pub fn on_click(app_handle: &AppHandle) {
|
||||
let tray_event = { Config::verge().latest().tray_event.clone() };
|
||||
let tray_event = tray_event.unwrap_or("main_window".into());
|
||||
match tray_event.as_str() {
|
||||
@@ -273,7 +321,10 @@ impl Tray {
|
||||
|
||||
pub fn on_system_tray_event(app_handle: &AppHandle, event: SystemTrayEvent) {
|
||||
match event {
|
||||
SystemTrayEvent::LeftClick { .. } => Tray::on_left_click(app_handle),
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
SystemTrayEvent::LeftClick { .. } => Tray::on_click(app_handle),
|
||||
#[cfg(target_os = "macos")]
|
||||
SystemTrayEvent::RightClick { .. } => Tray::on_click(app_handle),
|
||||
SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
|
||||
mode @ ("rule_mode" | "global_mode" | "direct_mode") => {
|
||||
let mode = &mode[0..mode.len() - 5];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
function main(params) {
|
||||
if (params.mode === "script") {
|
||||
params.mode = "rule";
|
||||
function main(config) {
|
||||
if (config.mode === "script") {
|
||||
config.mode = "rule";
|
||||
}
|
||||
return params;
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
function main(params) {
|
||||
if (Array.isArray(params.proxies)) {
|
||||
params.proxies.forEach((p, i) => {
|
||||
function main(config) {
|
||||
if (Array.isArray(config.proxies)) {
|
||||
config.proxies.forEach((p, i) => {
|
||||
if (p.type === "hysteria" && typeof p.alpn === "string") {
|
||||
params.proxies[i].alpn = [p.alpn];
|
||||
config.proxies[i].alpn = [p.alpn];
|
||||
}
|
||||
});
|
||||
}
|
||||
return params;
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -88,13 +88,13 @@ impl ChainItem {
|
||||
impl ChainSupport {
|
||||
pub fn is_support(&self, core: Option<&String>) -> bool {
|
||||
match core {
|
||||
Some(core) => match (self, core.as_str()) {
|
||||
(ChainSupport::All, _) => true,
|
||||
(ChainSupport::Clash, "clash") => true,
|
||||
(ChainSupport::ClashMeta, "clash-meta") => true,
|
||||
(ChainSupport::ClashMetaAlpha, "clash-meta-alpha") => true,
|
||||
_ => false,
|
||||
},
|
||||
Some(core) => matches!(
|
||||
(self, core.as_str()),
|
||||
(ChainSupport::All, _)
|
||||
| (ChainSupport::Clash, "clash")
|
||||
| (ChainSupport::ClashMeta, "clash-meta")
|
||||
| (ChainSupport::ClashMetaAlpha, "clash-meta-alpha")
|
||||
),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,11 +60,7 @@ pub fn use_sort(config: Mapping) -> Mapping {
|
||||
|
||||
let supported_keys: HashSet<&str> = HANDLE_FIELDS.into_iter().chain(DEFAULT_FIELDS).collect();
|
||||
|
||||
let config_keys: HashSet<&str> = config
|
||||
.keys()
|
||||
.filter_map(|e| e.as_str())
|
||||
.into_iter()
|
||||
.collect();
|
||||
let config_keys: HashSet<&str> = config.keys().filter_map(|e| e.as_str()).collect();
|
||||
|
||||
config_keys.difference(&supported_keys).for_each(|&key| {
|
||||
let key = Value::from(key);
|
||||
|
||||
@@ -1,64 +1,38 @@
|
||||
use super::{use_filter, use_lowercase};
|
||||
use serde_yaml::{self, Mapping, Sequence, Value};
|
||||
|
||||
const MERGE_FIELDS: [&str; 10] = [
|
||||
const MERGE_FIELDS: [&str; 6] = [
|
||||
"prepend-rules",
|
||||
"append-rules",
|
||||
"prepend-rule-providers",
|
||||
"append-rule-providers",
|
||||
"prepend-proxies",
|
||||
"append-proxies",
|
||||
"prepend-proxy-providers",
|
||||
"append-proxy-providers",
|
||||
"prepend-proxy-groups",
|
||||
"append-proxy-groups",
|
||||
];
|
||||
|
||||
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);
|
||||
});
|
||||
fn deep_merge(a: &mut Value, b: &Value) {
|
||||
match (a, b) {
|
||||
(&mut Value::Mapping(ref mut a), Value::Mapping(b)) => {
|
||||
for (k, v) in b {
|
||||
deep_merge(a.entry(k.clone()).or_insert(Value::Null), v);
|
||||
}
|
||||
}
|
||||
(a, b) => *a = b.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn use_merge(merge: Mapping, config: Mapping) -> Mapping {
|
||||
let mut config = Value::from(config);
|
||||
let mut merge_without_append = use_lowercase(merge.clone());
|
||||
for key in MERGE_FIELDS {
|
||||
merge_without_append.remove(key).unwrap_or_default();
|
||||
}
|
||||
deep_merge(&mut config, &Value::from(merge_without_append));
|
||||
|
||||
let mut config = config.as_mapping().unwrap().clone();
|
||||
let merge_list = MERGE_FIELDS.iter().map(|s| s.to_string());
|
||||
let merge = use_filter(merge, &merge_list.collect());
|
||||
|
||||
["rule-providers", "proxy-providers"]
|
||||
.iter()
|
||||
.for_each(|key_str| {
|
||||
let key_val = Value::from(key_str.to_string());
|
||||
|
||||
let mut map = Mapping::default();
|
||||
|
||||
map = config.get(&key_val).map_or(map.clone(), |val| {
|
||||
val.as_mapping().map_or(map, |v| v.clone())
|
||||
});
|
||||
|
||||
let pre_key = Value::from(format!("prepend-{key_str}"));
|
||||
let post_key = Value::from(format!("append-{key_str}"));
|
||||
|
||||
if let Some(pre_val) = merge.get(&pre_key) {
|
||||
if pre_val.is_mapping() {
|
||||
let mut pre_val = pre_val.as_mapping().unwrap().clone();
|
||||
pre_val.extend(map);
|
||||
map = pre_val;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(post_val) = merge.get(&post_key) {
|
||||
if post_val.is_mapping() {
|
||||
map.extend(post_val.as_mapping().unwrap().clone());
|
||||
}
|
||||
}
|
||||
|
||||
if !map.is_empty() {
|
||||
config.insert(key_val, Value::from(map));
|
||||
}
|
||||
});
|
||||
|
||||
["rules", "proxies", "proxy-groups"]
|
||||
.iter()
|
||||
.for_each(|key_str| {
|
||||
|
||||
@@ -22,15 +22,29 @@ pub fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||
// config.yaml 的订阅
|
||||
let clash_config = { Config::clash().latest().0.clone() };
|
||||
|
||||
let (clash_core, enable_tun, enable_builtin) = {
|
||||
let (clash_core, enable_tun, enable_builtin, socks_enabled, http_enabled) = {
|
||||
let verge = Config::verge();
|
||||
let verge = verge.latest();
|
||||
(
|
||||
verge.clash_core.clone(),
|
||||
verge.enable_tun_mode.unwrap_or(false),
|
||||
verge.enable_builtin_enhanced.unwrap_or(true),
|
||||
verge.verge_socks_enabled.unwrap_or(true),
|
||||
verge.verge_http_enabled.unwrap_or(true),
|
||||
)
|
||||
};
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let redir_enabled = {
|
||||
let verge = Config::verge();
|
||||
let verge = verge.latest();
|
||||
verge.verge_redir_enabled.unwrap_or(true)
|
||||
};
|
||||
#[cfg(target_os = "linux")]
|
||||
let tproxy_enabled = {
|
||||
let verge = Config::verge();
|
||||
let verge = verge.latest();
|
||||
verge.verge_tproxy_enabled.unwrap_or(true)
|
||||
};
|
||||
|
||||
// 从profiles里拿东西
|
||||
let (mut config, chain) = {
|
||||
@@ -88,6 +102,28 @@ pub fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||
}
|
||||
config.insert("tun".into(), tun.into());
|
||||
} else {
|
||||
if key.as_str() == Some("socks-port") && !socks_enabled {
|
||||
config.remove("socks-port");
|
||||
continue;
|
||||
}
|
||||
if key.as_str() == Some("port") && !http_enabled {
|
||||
config.remove("port");
|
||||
continue;
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
if key.as_str() == Some("redir-port") && !redir_enabled {
|
||||
config.remove("redir-port");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
if key.as_str() == Some("tproxy-port") && !tproxy_enabled {
|
||||
config.remove("tproxy-port");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
config.insert(key, value);
|
||||
}
|
||||
}
|
||||
@@ -100,17 +136,15 @@ pub fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||
.map(|(_, c)| c)
|
||||
.for_each(|item| {
|
||||
log::debug!(target: "app", "run builtin script {}", item.uid);
|
||||
|
||||
match item.data {
|
||||
ChainType::Script(script) => match use_script(script, config.to_owned()) {
|
||||
if let ChainType::Script(script) = item.data {
|
||||
match use_script(script, config.to_owned()) {
|
||||
Ok((res_config, _)) => {
|
||||
config = res_config;
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "builtin script error `{err}`");
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -119,7 +153,7 @@ pub fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||
config = use_sort(config);
|
||||
|
||||
let mut exists_set = HashSet::new();
|
||||
exists_set.extend(exists_keys.into_iter());
|
||||
exists_set.extend(exists_keys);
|
||||
exists_keys = exists_set.into_iter().collect();
|
||||
|
||||
(config, exists_keys, result_map)
|
||||
|
||||
@@ -16,7 +16,7 @@ pub fn use_script(script: String, config: Mapping) -> Result<(Mapping, Vec<(Stri
|
||||
2,
|
||||
NativeFunction::from_closure(
|
||||
move |_: &JsValue, args: &[JsValue], context: &mut Context| {
|
||||
let level = args.get(0).unwrap().to_string(context)?;
|
||||
let level = args.first().unwrap().to_string(context)?;
|
||||
let level = level.to_std_string().unwrap();
|
||||
let data = args.get(1).unwrap().to_string(context)?;
|
||||
let data = data.to_std_string().unwrap();
|
||||
|
||||
@@ -42,8 +42,19 @@ pub fn use_tun(mut config: Mapping, enable: bool) -> Mapping {
|
||||
let resource_dir = dirs::app_resources_dir().unwrap();
|
||||
let script = resource_dir.join("set_dns.sh");
|
||||
let script = script.to_string_lossy();
|
||||
match Command::new("bash").args([script]).output() {
|
||||
Ok(_) => log::info!(target: "app", "set system dns successfully"),
|
||||
match Command::new("bash")
|
||||
.args([script])
|
||||
.current_dir(resource_dir)
|
||||
.status()
|
||||
{
|
||||
Ok(status) => {
|
||||
if status.success() {
|
||||
log::info!(target: "app", "set system dns successfully");
|
||||
} else {
|
||||
let code = status.code().unwrap_or(-1);
|
||||
log::error!(target: "app", "set system dns failed: {code}");
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "set system dns failed: {err}");
|
||||
}
|
||||
@@ -59,8 +70,19 @@ pub fn use_tun(mut config: Mapping, enable: bool) -> Mapping {
|
||||
let resource_dir = dirs::app_resources_dir().unwrap();
|
||||
let script = resource_dir.join("unset_dns.sh");
|
||||
let script = script.to_string_lossy();
|
||||
match Command::new("bash").args([script]).output() {
|
||||
Ok(_) => log::info!(target: "app", "unset system dns successfully"),
|
||||
match Command::new("bash")
|
||||
.args([script])
|
||||
.current_dir(resource_dir)
|
||||
.status()
|
||||
{
|
||||
Ok(status) => {
|
||||
if status.success() {
|
||||
log::info!(target: "app", "unset system dns successfully");
|
||||
} else {
|
||||
let code = status.code().unwrap_or(-1);
|
||||
log::error!(target: "app", "unset system dns failed: {code}");
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "unset system dns failed: {err}");
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ pub fn toggle_tun_mode() {
|
||||
pub async fn patch_clash(patch: Mapping) -> Result<()> {
|
||||
Config::clash().draft().patch_config(patch.clone());
|
||||
|
||||
match {
|
||||
let res = {
|
||||
let redir_port = patch.get("redir-port");
|
||||
let tproxy_port = patch.get("tproxy-port");
|
||||
let mixed_port = patch.get("mixed-port");
|
||||
@@ -156,7 +156,8 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
|
||||
Config::runtime().latest().patch_config(patch);
|
||||
|
||||
<Result<()>>::Ok(())
|
||||
} {
|
||||
};
|
||||
match res {
|
||||
Ok(()) => {
|
||||
Config::clash().apply();
|
||||
Config::clash().data().save_config()?;
|
||||
@@ -177,37 +178,56 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
|
||||
let tun_mode = patch.enable_tun_mode;
|
||||
let auto_launch = patch.enable_auto_launch;
|
||||
let system_proxy = patch.enable_system_proxy;
|
||||
let pac = patch.proxy_auto_config;
|
||||
let pac_content = patch.pac_file_content;
|
||||
let proxy_bypass = patch.system_proxy_bypass;
|
||||
let language = patch.language;
|
||||
let port = patch.verge_mixed_port;
|
||||
#[cfg(target_os = "macos")]
|
||||
let tray_icon = patch.tray_icon;
|
||||
let common_tray_icon = patch.common_tray_icon;
|
||||
let sysproxy_tray_icon = patch.sysproxy_tray_icon;
|
||||
let tun_tray_icon = patch.tun_tray_icon;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let redir_enabled = patch.verge_redir_enabled;
|
||||
#[cfg(target_os = "linux")]
|
||||
let tproxy_enabled = patch.verge_tproxy_enabled;
|
||||
let socks_enabled = patch.verge_socks_enabled;
|
||||
let http_enabled = patch.verge_http_enabled;
|
||||
let res = {
|
||||
let service_mode = patch.enable_service_mode;
|
||||
|
||||
match {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let service_mode = patch.enable_service_mode;
|
||||
if service_mode.is_some() {
|
||||
log::debug!(target: "app", "change service mode to {}", service_mode.unwrap());
|
||||
|
||||
if service_mode.is_some() {
|
||||
log::debug!(target: "app", "change service mode to {}", service_mode.unwrap());
|
||||
|
||||
Config::generate()?;
|
||||
CoreManager::global().run_core().await?;
|
||||
} else if tun_mode.is_some() {
|
||||
update_core_config().await?;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
if tun_mode.is_some() {
|
||||
Config::generate()?;
|
||||
CoreManager::global().run_core().await?;
|
||||
} else if tun_mode.is_some() {
|
||||
update_core_config().await?;
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
if redir_enabled.is_some() {
|
||||
Config::generate()?;
|
||||
CoreManager::global().run_core().await?;
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
if tproxy_enabled.is_some() {
|
||||
Config::generate()?;
|
||||
CoreManager::global().run_core().await?;
|
||||
}
|
||||
if socks_enabled.is_some() || http_enabled.is_some() {
|
||||
Config::generate()?;
|
||||
CoreManager::global().run_core().await?;
|
||||
}
|
||||
if auto_launch.is_some() {
|
||||
sysopt::Sysopt::global().update_launch()?;
|
||||
}
|
||||
if system_proxy.is_some() || proxy_bypass.is_some() || port.is_some() {
|
||||
if system_proxy.is_some()
|
||||
|| proxy_bypass.is_some()
|
||||
|| port.is_some()
|
||||
|| pac.is_some()
|
||||
|| pac_content.is_some()
|
||||
{
|
||||
sysopt::Sysopt::global().update_sysproxy()?;
|
||||
sysopt::Sysopt::global().guard_proxy();
|
||||
}
|
||||
@@ -230,9 +250,14 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
|
||||
{
|
||||
handle::Handle::update_systray_part()?;
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
if tray_icon.is_some() {
|
||||
handle::Handle::update_systray_part()?;
|
||||
}
|
||||
|
||||
<Result<()>>::Ok(())
|
||||
} {
|
||||
};
|
||||
match res {
|
||||
Ok(()) => {
|
||||
Config::verge().apply();
|
||||
Config::verge().data().save_file()?;
|
||||
@@ -307,7 +332,7 @@ pub fn copy_clash_env(app_handle: &AppHandle) {
|
||||
|
||||
let sh =
|
||||
format!("export https_proxy={http_proxy} http_proxy={http_proxy} all_proxy={socks5_proxy}");
|
||||
let cmd: String = format!("set http_proxy={http_proxy} \n set https_proxy={http_proxy}");
|
||||
let cmd: String = format!("set http_proxy={http_proxy}\r\nset https_proxy={http_proxy}");
|
||||
let ps: String = format!("$env:HTTP_PROXY=\"{http_proxy}\"; $env:HTTPS_PROXY=\"{http_proxy}\"");
|
||||
|
||||
let mut cliboard = app_handle.clipboard_manager();
|
||||
@@ -362,11 +387,19 @@ pub async fn test_delay(url: String) -> Result<u32> {
|
||||
.get(url).header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0");
|
||||
let start = Instant::now();
|
||||
|
||||
let response = request.send().await?;
|
||||
if response.status().is_success() {
|
||||
let delay = start.elapsed().as_millis() as u32;
|
||||
Ok(delay)
|
||||
} else {
|
||||
Ok(10000u32)
|
||||
let response = request.send().await;
|
||||
match response {
|
||||
Ok(response) => {
|
||||
log::trace!(target: "app", "test_delay response: {:#?}", response);
|
||||
if response.status().is_success() {
|
||||
Ok(start.elapsed().as_millis() as u32)
|
||||
} else {
|
||||
Ok(10000u32)
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
log::trace!(target: "app", "test_delay error: {:#?}", err);
|
||||
Err(err.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ fn main() -> std::io::Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
|
||||
|
||||
crate::log_err!(init::init_config());
|
||||
|
||||
#[allow(unused_mut)]
|
||||
@@ -33,6 +36,7 @@ fn main() -> std::io::Result<()> {
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
// common
|
||||
cmds::get_sys_proxy,
|
||||
cmds::get_auto_proxy,
|
||||
cmds::open_app_dir,
|
||||
cmds::open_logs_dir,
|
||||
cmds::open_web_url,
|
||||
|
||||
@@ -92,12 +92,16 @@ pub fn clash_pid_path() -> Result<PathBuf> {
|
||||
Ok(app_home_dir()?.join("clash.pid"))
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn service_path() -> Result<PathBuf> {
|
||||
Ok(app_resources_dir()?.join("clash-verge-service"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn service_path() -> Result<PathBuf> {
|
||||
Ok(app_resources_dir()?.join("clash-verge-service.exe"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn service_log_file() -> Result<PathBuf> {
|
||||
use chrono::Local;
|
||||
|
||||
|
||||
@@ -135,13 +135,12 @@ pub fn delete_log() -> Result<()> {
|
||||
for file in fs::read_dir(&log_dir)?.flatten() {
|
||||
let _ = process_file(file);
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let service_log_dir = log_dir.join("service");
|
||||
for file in fs::read_dir(&service_log_dir)?.flatten() {
|
||||
let _ = process_file(file);
|
||||
}
|
||||
|
||||
let service_log_dir = log_dir.join("service");
|
||||
for file in fs::read_dir(service_log_dir)?.flatten() {
|
||||
let _ = process_file(file);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -305,7 +304,7 @@ pub fn startup_script() -> Result<()> {
|
||||
shell = "powershell";
|
||||
}
|
||||
if path.ends_with(".bat") {
|
||||
shell = "cmd";
|
||||
shell = "powershell";
|
||||
}
|
||||
if shell.is_empty() {
|
||||
return Err(anyhow::anyhow!("unsupported script: {path}"));
|
||||
@@ -319,11 +318,11 @@ pub fn startup_script() -> Result<()> {
|
||||
Some(dir) => {
|
||||
let _ = Command::new(shell)
|
||||
.current_dir(dir.to_path_buf())
|
||||
.args(&[path])
|
||||
.args([path])
|
||||
.output()?;
|
||||
}
|
||||
None => {
|
||||
let _ = Command::new(shell).args(&[path]).output()?;
|
||||
let _ = Command::new(shell).args([path]).output()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,3 +4,4 @@ pub mod init;
|
||||
pub mod resolve;
|
||||
pub mod server;
|
||||
pub mod tmpl;
|
||||
pub mod unix_helper;
|
||||
|
||||
@@ -99,9 +99,12 @@ pub fn resolve_setup(app: &mut App) {
|
||||
|
||||
let argvs: Vec<String> = std::env::args().collect();
|
||||
if argvs.len() > 1 {
|
||||
tauri::async_runtime::block_on(async {
|
||||
resolve_scheme(argvs[1].to_owned()).await;
|
||||
});
|
||||
let param = argvs[1].as_str();
|
||||
if param.starts_with("clash:") {
|
||||
tauri::async_runtime::block_on(async {
|
||||
resolve_scheme(argvs[1].to_owned()).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,11 +196,11 @@ pub fn create_window(app_handle: &AppHandle) {
|
||||
}
|
||||
Ok(center)
|
||||
})();
|
||||
|
||||
if center.unwrap_or(true) {
|
||||
trace_err!(win.center(), "set win center");
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
trace_err!(set_shadow(&win, true), "set win shadow");
|
||||
if is_maximized {
|
||||
trace_err!(win.maximize(), "set win maximize");
|
||||
@@ -205,7 +208,6 @@ pub fn create_window(app_handle: &AppHandle) {
|
||||
}
|
||||
Err(_) => {
|
||||
log::error!("failed to create window");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
extern crate warp;
|
||||
|
||||
use super::resolve;
|
||||
use crate::config::IVerge;
|
||||
use crate::config::{Config, IVerge, DEFAULT_PAC};
|
||||
use anyhow::{bail, Result};
|
||||
use port_scanner::local_port_available;
|
||||
use std::convert::Infallible;
|
||||
@@ -28,12 +28,14 @@ pub fn check_singleton() -> Result<()> {
|
||||
let argvs: Vec<String> = std::env::args().collect();
|
||||
if argvs.len() > 1 {
|
||||
let param = argvs[1].as_str();
|
||||
reqwest::get(format!(
|
||||
"http://127.0.0.1:{port}/commands/scheme?param={param}"
|
||||
))
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
if param.starts_with("clash:") {
|
||||
reqwest::get(format!(
|
||||
"http://127.0.0.1:{port}/commands/scheme?param={param}"
|
||||
))
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
}
|
||||
} else {
|
||||
reqwest::get(format!("http://127.0.0.1:{port}/commands/visible"))
|
||||
.await?
|
||||
@@ -64,6 +66,22 @@ pub fn embed_server(app_handle: AppHandle) {
|
||||
"ok"
|
||||
});
|
||||
|
||||
let pac = warp::path!("commands" / "pac").map(move || {
|
||||
let content = Config::verge()
|
||||
.latest()
|
||||
.pac_file_content
|
||||
.clone()
|
||||
.unwrap_or(DEFAULT_PAC.to_string());
|
||||
let port = Config::verge()
|
||||
.latest()
|
||||
.verge_mixed_port
|
||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||
let content = content.replace("%mixed-port%", &format!("{}", port));
|
||||
warp::http::Response::builder()
|
||||
.header("Content-Type", "application/x-ns-proxy-autoconfig")
|
||||
.body(content)
|
||||
.unwrap_or_default()
|
||||
});
|
||||
let scheme = warp::path!("commands" / "scheme")
|
||||
.and(warp::query::<QueryParam>())
|
||||
.and_then(scheme_handler);
|
||||
@@ -72,7 +90,7 @@ pub fn embed_server(app_handle: AppHandle) {
|
||||
resolve::resolve_scheme(query.param).await;
|
||||
Ok("ok")
|
||||
}
|
||||
let commands = ping.or(visible).or(scheme);
|
||||
let commands = ping.or(visible).or(pac).or(scheme);
|
||||
warp::serve(commands).run(([127, 0, 0, 1], port)).await;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,44 +1,35 @@
|
||||
//! Some config file template
|
||||
|
||||
/// template for new a profile item
|
||||
pub const ITEM_LOCAL: &str = "# Profile Template for clash verge
|
||||
pub const ITEM_LOCAL: &str = "# Profile Template for Clash Verge
|
||||
|
||||
proxies:
|
||||
proxies: []
|
||||
|
||||
proxy-groups:
|
||||
proxy-groups: []
|
||||
|
||||
rules:
|
||||
rules: []
|
||||
";
|
||||
|
||||
/// enhanced profile
|
||||
pub const ITEM_MERGE: &str = "# Merge Template for clash verge
|
||||
# The `Merge` format used to enhance profile
|
||||
pub const ITEM_MERGE: &str = "# Profile Enhancement Merge Template for Clash Verge
|
||||
|
||||
prepend-rules:
|
||||
prepend-rules: []
|
||||
|
||||
prepend-rule-providers:
|
||||
prepend-proxies: []
|
||||
|
||||
prepend-proxies:
|
||||
prepend-proxy-groups: []
|
||||
|
||||
prepend-proxy-providers:
|
||||
append-rules: []
|
||||
|
||||
prepend-proxy-groups:
|
||||
append-proxies: []
|
||||
|
||||
append-rules:
|
||||
|
||||
append-rule-providers:
|
||||
|
||||
append-proxies:
|
||||
|
||||
append-proxy-providers:
|
||||
|
||||
append-proxy-groups:
|
||||
append-proxy-groups: []
|
||||
";
|
||||
|
||||
/// enhanced profile
|
||||
pub const ITEM_SCRIPT: &str = "// Define the `main` function
|
||||
pub const ITEM_SCRIPT: &str = "// Define main function (script entry)
|
||||
|
||||
function main(params) {
|
||||
return params;
|
||||
function main(config) {
|
||||
return config;
|
||||
}
|
||||
";
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn linux_elevator() -> &'static str {
|
||||
use std::process::Command;
|
||||
match Command::new("which").arg("pkexec").output() {
|
||||
Ok(output) => {
|
||||
if output.stdout.is_empty() {
|
||||
"sudo"
|
||||
} else {
|
||||
"pkexec"
|
||||
}
|
||||
}
|
||||
Err(_) => "sudo",
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"package": {
|
||||
"productName": "Clash Verge",
|
||||
"version": "1.5.10"
|
||||
"version": "1.6.6"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
@@ -17,7 +18,7 @@
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon-new.icns",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"resources": ["resources"],
|
||||
@@ -61,15 +62,20 @@
|
||||
},
|
||||
"protocol": {
|
||||
"asset": true,
|
||||
"assetScope": ["$APPDATA/**", "$RESOURCE/../**"]
|
||||
"assetScope": ["$APPDATA/**", "$RESOURCE/../**", "**"]
|
||||
},
|
||||
"path": {
|
||||
"all": true
|
||||
},
|
||||
"fs": {
|
||||
"exists": true,
|
||||
"readFile": true,
|
||||
"scope": ["$APPDATA/**", "$RESOURCE/../**", "**"]
|
||||
}
|
||||
},
|
||||
"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 asset: http: https: data: 'self';"
|
||||
"csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: asset: 'unsafe-eval' 'unsafe-inline' 'self';"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"tauri": {
|
||||
"systemTray": {
|
||||
"iconPath": "icons/tray-icon.png"
|
||||
"iconPath": "icons/tray-icon.ico"
|
||||
},
|
||||
"bundle": {
|
||||
"targets": ["deb", "appimage", "updater"],
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"targets": ["deb", "rpm"],
|
||||
"deb": {
|
||||
"depends": ["openssl"],
|
||||
"desktopTemplate": "./template/clash-verge.desktop"
|
||||
"desktopTemplate": "./template/clash-verge.desktop",
|
||||
"provides": ["clash-verge", "clash-meta"],
|
||||
"conflicts": ["clash-verge", "clash-meta"],
|
||||
"replaces": ["clash-verge", "clash-meta"]
|
||||
},
|
||||
"rpm": {
|
||||
"depends": ["openssl"],
|
||||
"desktopTemplate": "./template/clash-verge.desktop",
|
||||
"provides": ["clash-verge", "clash-meta"],
|
||||
"conflicts": ["clash-verge", "clash-meta"],
|
||||
"obsoletes": ["clash-verge", "clash-meta"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"tauri": {
|
||||
"systemTray": {
|
||||
"iconPath": "icons/mac-tray-icon.png",
|
||||
"iconPath": "icons/tray-icon-mono.ico",
|
||||
"iconAsTemplate": true
|
||||
},
|
||||
"bundle": {
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"targets": ["app", "dmg", "updater"],
|
||||
"macOS": {
|
||||
"frameworks": [],
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"tauri": {
|
||||
"systemTray": {
|
||||
"iconPath": "icons/tray-icon.png"
|
||||
"iconPath": "icons/tray-icon.ico"
|
||||
},
|
||||
"bundle": {
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"targets": ["nsis", "updater"],
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
|
||||
@@ -13,8 +13,9 @@ Unicode true
|
||||
!include FileFunc.nsh
|
||||
!include x64.nsh
|
||||
!include WordFunc.nsh
|
||||
!include "LogicLib.nsh"
|
||||
!include "StrFunc.nsh"
|
||||
!include "Win\COM.nsh"
|
||||
!include "Win\Propkey.nsh"
|
||||
!addplugindir "$%AppData%\Local\NSIS\"
|
||||
${StrCase}
|
||||
${StrLoc}
|
||||
@@ -149,7 +150,6 @@ Function PageReinstall
|
||||
; however, this should be fine since the user will have to confirm the uninstallation
|
||||
; and they can chose to abort it if doesn't make sense.
|
||||
StrCpy $0 0
|
||||
|
||||
wix_loop:
|
||||
EnumRegKey $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" $0
|
||||
StrCmp $1 "" wix_done ; Exit loop if there is no more keys to loop on
|
||||
@@ -323,10 +323,15 @@ Var AppStartMenuFolder
|
||||
!define MUI_FINISHPAGE_SHOWREADME_TEXT "$(createDesktop)"
|
||||
!define MUI_FINISHPAGE_SHOWREADME_FUNCTION CreateDesktopShortcut
|
||||
; Show run app after installation.
|
||||
!define MUI_FINISHPAGE_RUN "$INSTDIR\${MAINBINARYNAME}.exe"
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION RunMainBinary
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfPassive
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
Function RunMainBinary
|
||||
nsis_tauri_utils::RunAsUser "$INSTDIR\${MAINBINARYNAME}.exe" ""
|
||||
FunctionEnd
|
||||
|
||||
; Uninstaller Pages
|
||||
; 1. Confirm uninstall page
|
||||
Var DeleteAppDataCheckbox
|
||||
@@ -420,55 +425,53 @@ Function .onInit
|
||||
FunctionEnd
|
||||
|
||||
!macro CheckAllVergeProcesses
|
||||
; Check if Clash Verge.exe is running
|
||||
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
|
||||
nsis_tauri_utils::KillProcess "Clash Verge.exe"
|
||||
!endif
|
||||
${EndIf}
|
||||
|
||||
|
||||
; Check if clash-verge-service.exe is running
|
||||
; Check if clash-verge-service.exe is running
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::FindProcessCurrentUser "clash-verge-service.exe"
|
||||
!else
|
||||
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
|
||||
nsis_tauri_utils::KillProcess "clash-verge-service.exe"
|
||||
!endif
|
||||
${EndIf}
|
||||
!endif
|
||||
Pop $R0
|
||||
${If} $R0 = 0
|
||||
DetailPrint "Kill clash-verge-service.exe..."
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "clash-verge-service.exe"
|
||||
!else
|
||||
nsis_tauri_utils::KillProcess "clash-verge-service.exe"
|
||||
!endif
|
||||
${EndIf}
|
||||
|
||||
|
||||
; Check if clash-meta-alpha.exe is running
|
||||
; Check if clash-meta-alpha.exe is running
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::FindProcessCurrentUser "clash-meta-alpha.exe"
|
||||
!else
|
||||
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
|
||||
nsis_tauri_utils::KillProcess "clash-meta-alpha.exe"
|
||||
!endif
|
||||
${EndIf}
|
||||
!endif
|
||||
Pop $R0
|
||||
${If} $R0 = 0
|
||||
DetailPrint "Kill clash-meta-alpha.exe..."
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "clash-meta-alpha.exe"
|
||||
!else
|
||||
nsis_tauri_utils::KillProcess "clash-meta-alpha.exe"
|
||||
!endif
|
||||
${EndIf}
|
||||
|
||||
; Check if clash-meta.exe is running
|
||||
; Check if clash-meta.exe is running
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::FindProcessCurrentUser "clash-meta.exe"
|
||||
!else
|
||||
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
|
||||
nsis_tauri_utils::KillProcess "clash-meta.exe"
|
||||
!endif
|
||||
${EndIf}
|
||||
!endif
|
||||
Pop $R0
|
||||
${If} $R0 = 0
|
||||
DetailPrint "Kill clash-meta.exe..."
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "clash-meta.exe"
|
||||
!else
|
||||
nsis_tauri_utils::KillProcess "clash-meta.exe"
|
||||
!endif
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
!macro StartVergeService
|
||||
@@ -571,7 +574,7 @@ Section WebView2
|
||||
!if "${INSTALLWEBVIEW2MODE}" == "downloadBootstrapper"
|
||||
Delete "$TEMP\MicrosoftEdgeWebview2Setup.exe"
|
||||
DetailPrint "$(webview2Downloading)"
|
||||
nsis_tauri_utils::download "https://go.microsoft.com/fwlink/p/?LinkId=2124703" "$TEMP\MicrosoftEdgeWebview2Setup.exe"
|
||||
NSISdl::download "https://go.microsoft.com/fwlink/p/?LinkId=2124703" "$TEMP\MicrosoftEdgeWebview2Setup.exe"
|
||||
Pop $0
|
||||
${If} $0 == 0
|
||||
DetailPrint "$(webview2DownloadSuccess)"
|
||||
@@ -730,7 +733,8 @@ Function .onInstSuccess
|
||||
check_r_flag:
|
||||
${GetOptions} $CMDLINE "/R" $R0
|
||||
IfErrors run_done 0
|
||||
Exec '"$INSTDIR\${MAINBINARYNAME}.exe"'
|
||||
${GetOptions} $CMDLINE "/ARGS" $R0
|
||||
nsis_tauri_utils::RunAsUser "$INSTDIR\${MAINBINARYNAME}.exe" "$R0"
|
||||
run_done:
|
||||
FunctionEnd
|
||||
|
||||
@@ -744,6 +748,35 @@ Function un.onInit
|
||||
!insertmacro MUI_UNGETLANGUAGE
|
||||
FunctionEnd
|
||||
|
||||
!macro DeleteAppUserModelId
|
||||
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_DestinationList} ${IID_ICustomDestinationList} r1 ""
|
||||
${If} $1 P<> 0
|
||||
${ICustomDestinationList::DeleteList} $1 '("${BUNDLEID}")'
|
||||
${IUnknown::Release} $1 ""
|
||||
${EndIf}
|
||||
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_ApplicationDestinations} ${IID_IApplicationDestinations} r1 ""
|
||||
${If} $1 P<> 0
|
||||
${IApplicationDestinations::SetAppID} $1 '("${BUNDLEID}")i.r0'
|
||||
${If} $0 >= 0
|
||||
${IApplicationDestinations::RemoveAllDestinations} $1 ''
|
||||
${EndIf}
|
||||
${IUnknown::Release} $1 ""
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
; From https://stackoverflow.com/a/42816728/16993372
|
||||
!macro UnpinShortcut shortcut
|
||||
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_StartMenuPin} ${IID_IStartMenuPinnedList} r0 ""
|
||||
${If} $0 P<> 0
|
||||
System::Call 'SHELL32::SHCreateItemFromParsingName(ws, p0, g "${IID_IShellItem}", *p0r1)' "${shortcut}"
|
||||
${If} $1 P<> 0
|
||||
${IStartMenuPinnedList::RemoveFromList} $0 '(r1)'
|
||||
${IUnknown::Release} $1 ""
|
||||
${EndIf}
|
||||
${IUnknown::Release} $0 ""
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
Section Uninstall
|
||||
!insertmacro CheckIfAppIsRunning
|
||||
!insertmacro CheckAllVergeProcesses
|
||||
@@ -756,7 +789,7 @@ Section Uninstall
|
||||
{{#each resources}}
|
||||
Delete "$INSTDIR\\{{this.[1]}}"
|
||||
{{/each}}
|
||||
|
||||
Delete "$INSTDIR\resources"
|
||||
; Delete external binaries
|
||||
{{#each binaries}}
|
||||
Delete "$INSTDIR\\{{this}}"
|
||||
@@ -765,14 +798,14 @@ Section Uninstall
|
||||
; Delete uninstaller
|
||||
Delete "$INSTDIR\uninstall.exe"
|
||||
|
||||
${If} $DeleteAppDataCheckboxState == 1
|
||||
RMDir /R /REBOOTOK "$INSTDIR"
|
||||
${Else}
|
||||
{{#each resources_ancestors}}
|
||||
RMDir /REBOOTOK "$INSTDIR\\{{this}}"
|
||||
{{/each}}
|
||||
RMDir "$INSTDIR"
|
||||
${EndIf}
|
||||
{{#each resources_ancestors}}
|
||||
RMDir /REBOOTOK "$INSTDIR\\{{this}}"
|
||||
{{/each}}
|
||||
RMDir "$INSTDIR"
|
||||
|
||||
!insertmacro DeleteAppUserModelId
|
||||
!insertmacro UnpinShortcut "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk"
|
||||
!insertmacro UnpinShortcut "$DESKTOP\${MAINBINARYNAME}.lnk"
|
||||
|
||||
; Remove start menu shortcut
|
||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $AppStartMenuFolder
|
||||
@@ -815,13 +848,39 @@ Function SkipIfPassive
|
||||
${IfThen} $PassiveMode == 1 ${|} Abort ${|}
|
||||
FunctionEnd
|
||||
|
||||
!macro SetLnkAppUserModelId shortcut
|
||||
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_ShellLink} ${IID_IShellLink} r0 ""
|
||||
${If} $0 P<> 0
|
||||
${IUnknown::QueryInterface} $0 '("${IID_IPersistFile}",.r1)'
|
||||
${If} $1 P<> 0
|
||||
${IPersistFile::Load} $1 '("${shortcut}", ${STGM_READWRITE})'
|
||||
${IUnknown::QueryInterface} $0 '("${IID_IPropertyStore}",.r2)'
|
||||
${If} $2 P<> 0
|
||||
System::Call 'Oleaut32::SysAllocString(w "${BUNDLEID}") i.r3'
|
||||
System::Call '*${SYSSTRUCT_PROPERTYKEY}(${PKEY_AppUserModel_ID})p.r4'
|
||||
System::Call '*${SYSSTRUCT_PROPVARIANT}(${VT_BSTR},,&i4 $3)p.r5'
|
||||
${IPropertyStore::SetValue} $2 '($4,$5)'
|
||||
|
||||
System::Call 'Oleaut32::SysFreeString($3)'
|
||||
System::Free $4
|
||||
System::Free $5
|
||||
${IPropertyStore::Commit} $2 ""
|
||||
${IUnknown::Release} $2 ""
|
||||
${IPersistFile::Save} $1 '("${shortcut}",1)'
|
||||
${EndIf}
|
||||
${IUnknown::Release} $1 ""
|
||||
${EndIf}
|
||||
${IUnknown::Release} $0 ""
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
Function CreateDesktopShortcut
|
||||
CreateShortcut "$DESKTOP\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe"
|
||||
ApplicationID::Set "$DESKTOP\${MAINBINARYNAME}.lnk" "${BUNDLEID}"
|
||||
!insertmacro SetLnkAppUserModelId "$DESKTOP\${MAINBINARYNAME}.lnk"
|
||||
FunctionEnd
|
||||
|
||||
Function CreateStartMenuShortcut
|
||||
CreateDirectory "$SMPROGRAMS\$AppStartMenuFolder"
|
||||
CreateShortcut "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe"
|
||||
ApplicationID::Set "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk" "${BUNDLEID}"
|
||||
!insertmacro SetLnkAppUserModelId "$SMPROGRAMS\$AppStartMenuFolder\${MAINBINARYNAME}.lnk"
|
||||
FunctionEnd
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"tauri": {
|
||||
"systemTray": {
|
||||
"iconPath": "icons/tray-icon.ico"
|
||||
},
|
||||
"bundle": {
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"targets": ["nsis", "updater"],
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": "",
|
||||
"webviewInstallMode": {
|
||||
"type": "fixedRuntime",
|
||||
"path": "./Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.arm64/"
|
||||
},
|
||||
"nsis": {
|
||||
"displayLanguageSelector": true,
|
||||
"installerIcon": "icons/icon.ico",
|
||||
"languages": ["SimpChinese", "English"],
|
||||
"license": "../LICENSE",
|
||||
"installMode": "perMachine",
|
||||
"template": "./template/installer.nsi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"updater": {
|
||||
"active": true,
|
||||
"dialog": false,
|
||||
"endpoints": [
|
||||
"https://mirror.ghproxy.com/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2-proxy.json",
|
||||
"https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2.json"
|
||||
],
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"tauri": {
|
||||
"systemTray": {
|
||||
"iconPath": "icons/tray-icon.ico"
|
||||
},
|
||||
"bundle": {
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"targets": ["nsis", "updater"],
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": "",
|
||||
"webviewInstallMode": {
|
||||
"type": "fixedRuntime",
|
||||
"path": "./Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.x64/"
|
||||
},
|
||||
"nsis": {
|
||||
"displayLanguageSelector": true,
|
||||
"installerIcon": "icons/icon.ico",
|
||||
"languages": ["SimpChinese", "English"],
|
||||
"license": "../LICENSE",
|
||||
"installMode": "perMachine",
|
||||
"template": "./template/installer.nsi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"updater": {
|
||||
"active": true,
|
||||
"dialog": false,
|
||||
"endpoints": [
|
||||
"https://mirror.ghproxy.com/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2-proxy.json",
|
||||
"https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2.json"
|
||||
],
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"tauri": {
|
||||
"systemTray": {
|
||||
"iconPath": "icons/tray-icon.ico"
|
||||
},
|
||||
"bundle": {
|
||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||
"targets": ["nsis", "updater"],
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": "",
|
||||
"webviewInstallMode": {
|
||||
"type": "fixedRuntime",
|
||||
"path": "./Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.x86/"
|
||||
},
|
||||
"nsis": {
|
||||
"displayLanguageSelector": true,
|
||||
"installerIcon": "icons/icon.ico",
|
||||
"languages": ["SimpChinese", "English"],
|
||||
"license": "../LICENSE",
|
||||
"installMode": "perMachine",
|
||||
"template": "./template/installer.nsi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"updater": {
|
||||
"active": true,
|
||||
"dialog": false,
|
||||
"endpoints": [
|
||||
"https://mirror.ghproxy.com/https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2-proxy.json",
|
||||
"https://github.com/clash-verge-rev/clash-verge-rev/releases/download/updater/update-fixed-webview2.json"
|
||||
],
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M 175.755 768.851 L 334.113 343.826 L 394.912 343.826 L 554.501 768.851 L 494.851 768.851 L 453.989 653.897 L 275.036 653.897 L 234.583 768.851 L 175.755 768.851 Z M 293.332 604.339 L 436.102 604.339 L 366.441 406.757 L 362.994 406.757 L 293.332 604.339 Z M 703.344 780.174 C 670.415 780.174 644.541 771.518 625.724 754.205 C 606.907 736.892 597.499 713.412 597.499 683.764 C 597.499 653.898 608.575 629.61 630.729 610.902 C 652.882 592.195 681.682 582.842 717.129 582.842 C 732.663 582.842 747.433 584.223 761.437 586.985 C 775.44 589.747 787.419 593.973 797.375 599.662 L 797.375 580.626 C 797.375 557.323 790.66 539.299 777.231 526.554 C 763.802 513.808 744.753 507.435 720.082 507.435 C 705.423 507.435 691.652 510.293 678.769 516.01 C 665.887 521.726 654.004 530.218 643.118 541.486 L 607.099 512.687 C 621.43 495.948 637.95 483.422 656.657 475.107 C 675.365 466.793 696.726 462.636 720.739 462.636 C 762.639 462.636 794.365 472.988 815.918 493.693 C 837.469 514.397 848.245 544.797 848.245 584.893 L 848.245 770.574 L 798.031 770.574 L 798.031 731.025 L 794.421 731.025 C 784.903 746.889 772.39 759.046 756.882 767.498 C 741.375 775.948 723.529 780.174 703.344 780.174 Z M 709.087 736.688 C 734.031 736.688 754.981 727.594 771.939 709.406 C 788.896 691.218 797.375 668.694 797.375 641.836 C 787.693 636.147 776.315 631.812 763.242 628.831 C 750.168 625.849 737.751 624.358 725.99 624.358 C 701.594 624.358 682.735 629.555 669.415 639.949 C 656.096 650.342 649.436 664.947 649.436 683.764 C 649.436 699.628 654.906 712.414 665.846 722.124 C 676.786 731.833 691.2 736.688 709.087 736.688 Z"
|
||||
p-id="11663" transform="matrix(1, 0, 0, 1, 0, 3.552713678800501e-15)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M 64.002 831.066 L 64.002 649.735 L 128 649.735 L 128 767.067 L 896 767.067 L 896 649.735 L 959.999 649.735 L 959.999 831.066 L 64.001 831.066 L 64.002 831.066 Z M 414.031 680.257 L 414.031 640.708 L 410.421 640.708 C 400.903 656.571 388.39 668.729 372.882 677.18 C 357.375 685.631 339.529 689.857 319.344 689.857 C 286.688 689.857 260.883 681.2 241.929 663.887 C 222.975 646.575 213.499 623.095 213.499 593.447 C 213.499 563.58 224.575 539.293 246.729 520.585 C 268.883 501.878 297.546 492.524 332.719 492.524 C 348.254 492.524 363.023 493.905 377.026 496.667 C 391.029 499.43 403.146 503.656 413.375 509.345 L 413.375 490.309 C 413.375 467.006 406.729 448.982 393.437 436.236 C 380.144 423.49 361.299 417.117 336.902 417.117 C 321.969 417.117 307.993 419.976 294.975 425.692 C 281.956 431.408 270.004 439.9 259.118 451.169 L 223.099 422.37 C 237.43 405.631 253.95 393.104 272.657 384.79 C 291.365 376.476 312.862 372.318 337.149 372.318 C 379.05 372.318 410.708 382.671 432.123 403.375 C 453.538 424.079 464.245 454.479 464.245 494.575 L 464.245 680.257 L 414.031 680.257 Z M 341.99 534.041 C 317.867 534.041 299.077 539.238 285.62 549.631 C 272.164 560.024 265.436 574.493 265.436 593.036 C 265.436 609.174 270.974 622.097 282.051 631.806 C 293.128 641.516 307.61 646.371 325.498 646.371 C 350.441 646.371 371.323 637.277 388.144 619.089 C 404.965 600.9 413.375 578.377 413.375 551.518 C 403.693 545.83 392.315 541.495 379.242 538.514 C 366.168 535.532 353.751 534.041 341.99 534.041 Z M 541.375 680.667 L 541.375 252.934 L 593.558 252.934 L 593.558 384.545 L 590.358 427.211 L 593.148 427.211 C 598.564 418.733 608.943 408.435 624.287 396.319 C 639.631 384.203 660.977 378.145 688.327 378.145 C 729.735 378.145 762.638 393.27 787.035 423.519 C 811.431 453.769 823.629 491.047 823.629 535.355 C 823.629 579.116 811.609 615.874 787.568 645.631 C 763.527 675.389 730.31 690.267 687.917 690.267 C 662.044 690.267 641.258 684.688 625.558 673.529 C 609.859 662.37 599.056 651.594 593.148 641.201 L 590.358 641.201 L 590.358 680.667 L 541.375 680.667 Z M 681.6 426.801 C 653.702 426.801 631.521 437.563 615.056 459.087 C 598.591 480.613 590.358 505.816 590.358 534.698 C 590.358 564.018 598.591 589.263 615.056 610.433 C 631.521 631.602 653.702 642.186 681.6 642.186 C 709.497 642.186 731.309 631.807 747.036 611.048 C 762.762 590.289 770.625 564.839 770.625 534.698 C 770.625 504.558 762.762 479.04 747.036 458.145 C 731.309 437.249 709.497 426.801 681.6 426.801 Z"
|
||||
p-id="12920" transform="matrix(1, 0, 0, 1, 0, 1.4210854715202004e-14)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M 838.757 427.686 L 808.603 338.337 L 633.84 409.02 L 645.314 217.721 L 549.541 217.721 L 561.015 409.02 L 386.252 338.337 L 356.098 427.686 L 539.205 477.619 L 413.277 620.027 L 487.146 678.203 L 597.428 519.119 L 706.666 678.203 L 780.535 620.027 L 654.607 477.619 L 838.757 427.686 Z"
|
||||
p-id="15003" style="transform-origin: 597.428px 447.962px;" />
|
||||
<path
|
||||
d="M 185.244 735.674 C 185.244 789.945 243.994 823.864 290.994 796.729 C 312.807 784.135 326.244 760.861 326.244 735.674 C 326.244 681.403 267.494 647.484 220.494 674.619 C 198.681 687.213 185.244 710.487 185.244 735.674 Z"
|
||||
p-id="15004" style="transform-origin: 255.744px 735.674px;" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 803 B |
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0.00 0.00 512.00 512.00"
|
||||
width="512.00" height="512.00">
|
||||
<path fill="#ffffff"
|
||||
d=" M 45.65 297.77 C 50.31 280.20 56.48 263.74 64.10 247.67 C 66.07 243.51 65.99 238.92 65.73 234.44 Q 63.32 191.66 64.13 148.11 C 64.39 134.30 66.21 57.13 87.19 55.68 Q 94.10 55.20 99.69 57.92 Q 109.79 62.83 121.61 72.92 C 143.03 91.20 162.36 112.69 183.36 130.92 C 186.54 133.67 193.35 138.99 197.10 138.76 Q 198.57 138.67 200.07 138.26 Q 222.12 132.30 238.17 131.29 C 256.93 130.11 277.29 130.43 296.13 134.49 Q 305.05 136.41 313.24 138.56 C 318.37 139.92 325.54 133.72 329.51 130.33 Q 339.55 121.75 347.99 113.37 C 364.54 96.94 380.60 80.49 399.04 66.35 C 403.86 62.66 409.75 58.98 415.36 56.95 C 419.03 55.63 425.97 54.84 429.34 57.30 C 433.77 60.52 436.73 66.64 438.49 71.86 Q 441.73 81.45 443.26 90.82 Q 447.60 117.52 448.00 151.51 Q 448.45 189.74 447.59 207.00 Q 446.70 225.12 446.21 240.03 C 446.12 242.85 446.89 245.55 448.09 248.07 Q 459.73 272.71 466.27 297.70 C 467.59 302.75 468.45 308.08 467.82 313.31 C 466.21 326.87 459.76 339.57 452.24 350.80 Q 436.72 374.00 411.37 395.51 Q 374.63 426.67 330.92 443.23 Q 272.04 465.54 211.41 452.34 Q 188.54 447.36 165.13 436.61 Q 121.44 416.54 86.71 382.78 Q 69.63 366.18 57.73 347.55 C 50.80 336.69 44.86 323.90 44.03 311.09 Q 43.65 305.29 45.65 297.77 Z M 131.34 313.94 C 140.29 332.22 157.72 341.20 177.30 342.68 Q 184.65 343.24 193.22 340.65 Q 202.03 338.00 205.56 330.26 C 211.13 318.09 200.76 303.01 191.81 296.02 C 179.37 286.31 161.98 280.10 146.19 280.97 Q 137.21 281.47 131.35 287.14 C 124.01 294.24 127.17 305.43 131.34 313.94 Z M 349.22 281.81 C 332.78 284.95 316.93 292.71 307.08 305.92 C 303.14 311.22 300.42 317.96 301.07 324.43 C 302.18 335.36 310.18 340.08 320.43 341.92 C 336.31 344.78 355.06 339.00 366.59 328.03 C 376.14 318.95 389.80 294.29 373.19 284.22 C 366.55 280.20 356.95 280.33 349.22 281.81 Z M 226.25 381.62 C 232.99 389.35 240.71 395.69 249.97 398.50 C 259.93 401.51 272.87 391.21 279.39 384.18 C 281.43 381.98 283.70 379.66 284.61 376.72 C 285.41 374.13 282.30 371.54 280.28 370.59 Q 276.07 368.62 271.56 368.03 Q 254.57 365.79 237.08 367.97 Q 232.61 368.53 228.23 370.40 C 225.86 371.41 222.31 374.22 223.50 377.19 Q 224.45 379.55 226.25 381.62 Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0.00 0.00 512.00 512.00"
|
||||
width="512.00" height="512.00">
|
||||
<path fill="#000000"
|
||||
d=" M 66.75 243.26 C 64.36 202.61 63.47 160.98 66.14 119.90 Q 67.07 105.54 69.56 90.86 C 71.35 80.37 74.26 67.20 81.13 59.68 C 88.86 51.20 102.34 59.42 109.45 64.46 Q 122.61 73.79 137.56 88.26 Q 154.16 104.32 170.37 120.15 Q 177.39 127.01 185.78 133.69 C 189.58 136.71 194.75 140.48 199.81 139.03 Q 256.12 122.89 312.63 139.17 C 317.17 140.47 322.43 136.89 326.29 133.81 Q 334.64 127.18 341.86 120.15 Q 358.44 104.02 373.87 89.06 Q 389.67 73.75 403.99 63.72 Q 409.86 59.61 416.68 57.20 C 430.17 52.45 435.71 64.65 438.76 74.78 Q 442.82 88.24 444.57 104.64 Q 447.71 133.95 447.66 168.99 Q 447.61 205.59 445.24 243.61 Q 445.21 244.12 445.44 244.57 Q 459.30 271.43 466.56 302.09 C 469.00 312.41 465.64 324.20 461.06 333.82 C 449.65 357.80 430.14 378.99 409.62 396.13 Q 372.77 426.90 329.61 443.00 Q 266.07 466.70 201.80 449.27 C 162.55 438.62 125.61 417.06 95.28 389.88 C 77.45 373.90 60.60 354.63 50.57 332.92 C 46.30 323.66 43.03 312.16 45.33 302.37 Q 52.57 271.58 66.46 244.63 Q 66.80 243.98 66.75 243.26 Z M 129.31 310.72 Q 136.38 328.58 152.74 336.68 C 165.31 342.91 181.44 345.53 194.60 340.75 C 211.72 334.54 209.96 316.29 200.74 304.29 C 190.53 291.00 173.63 283.30 157.10 280.73 C 136.41 277.52 120.03 287.25 129.31 310.72 Z M 304.10 309.36 C 297.35 321.61 299.56 335.79 313.93 340.88 C 326.42 345.31 342.09 343.01 354.08 337.35 Q 374.66 327.63 380.68 304.95 C 386.50 282.97 365.69 278.03 349.30 281.14 C 331.39 284.54 312.80 293.56 304.10 309.36 Z M 244.39 396.99 Q 252.76 401.23 260.59 398.28 Q 271.64 394.13 281.68 382.89 C 290.72 372.77 280.23 368.82 272.04 367.56 Q 253.06 364.63 234.76 367.80 C 228.71 368.85 218.66 372.23 224.67 380.57 Q 231.98 390.72 244.39 396.99 Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 57 KiB |
@@ -1,18 +0,0 @@
|
||||
<svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400"
|
||||
height="400" viewBox="0, 0, 400,400">
|
||||
<defs>
|
||||
<linearGradient id="Gradient2" x1="0" x2="-0.1" y1="0" y2="1">
|
||||
<stop offset="0%" stop-color="#5b5c9d" />
|
||||
<stop offset="80%" stop-color="rgb(63, 64, 109)" />
|
||||
<stop offset="100%" stop-color="rgb(63, 64, 109)" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g id="svgg">
|
||||
<path id="path0"
|
||||
d="M118.124 39.858 C 116.645 40.182,114.562 42.930,113.283 46.247 C 111.908 49.812,110.887 54.542,107.205 74.400 C 106.736 76.930,105.926 81.160,105.404 83.800 C 104.527 88.237,103.654 92.889,102.177 101.000 C 101.856 102.760,101.413 105.100,101.192 106.200 C 100.754 108.375,100.784 108.199,98.436 122.200 C 96.675 132.702,95.947 137.215,94.984 143.600 C 94.636 145.910,94.098 149.420,93.789 151.400 C 92.649 158.697,91.961 164.413,92.180 164.768 C 92.304 164.968,92.223 165.192,92.000 165.266 C 91.777 165.340,96.852 165.347,103.277 165.282 C 116.520 165.149,115.721 165.379,116.358 161.519 C 122.839 122.279,179.334 121.580,186.617 160.650 C 186.981 162.602,187.463 164.425,187.689 164.700 C 188.328 165.481,229.717 165.423,230.367 164.640 C 230.622 164.332,231.013 162.937,231.235 161.540 C 237.531 121.949,295.239 121.807,301.620 161.367 C 302.274 165.421,301.855 165.252,310.962 165.117 C 315.273 165.052,318.861 165.090,318.935 165.200 C 319.009 165.310,319.005 165.152,318.927 164.848 C 318.849 164.545,318.519 162.610,318.193 160.548 C 317.867 158.487,317.330 155.135,317.000 153.100 C 316.162 147.934,315.312 142.663,314.823 139.600 C 314.595 138.170,314.226 136.010,314.004 134.800 C 313.781 133.590,312.423 125.400,310.985 116.600 C 304.278 75.545,304.008 74.156,298.145 50.400 C 295.961 41.553,294.621 39.584,290.800 39.611 C 287.927 39.631,283.053 43.395,279.420 48.400 C 277.509 51.032,261.566 79.109,256.960 87.953 C 253.991 93.654,253.647 93.789,245.600 92.402 C 218.757 87.774,194.454 87.780,170.478 92.420 C 162.868 93.893,163.987 94.596,157.579 84.306 C 133.879 46.247,126.566 38.009,118.124 39.858 M147.277 134.807 C 123.365 138.118,111.083 165.918,124.948 185.349 C 140.543 207.202,173.704 202.274,182.466 176.800 C 190.000 154.900,170.471 131.596,147.277 134.807 M262.051 134.810 C 235.780 138.440,224.730 170.720,243.356 189.422 C 264.398 210.548,299.874 195.275,298.689 165.600 C 297.927 146.523,280.892 132.207,262.051 134.810 M157.600 153.840 C 163.092 156.341,166.343 161.914,165.902 168.074 C 164.875 182.425,145.082 186.221,138.715 173.287 C 132.759 161.189,145.324 148.250,157.600 153.840 M273.193 153.597 C 279.788 156.926,283.287 165.159,280.844 171.600 C 275.229 186.406,253.594 183.910,252.135 168.287 C 251.125 157.467,263.609 148.758,273.193 153.597 M91.200 168.809 C 91.200 169.522,90.939 171.836,90.621 173.952 C 89.933 178.523,87.567 196.170,85.788 210.000 C 85.462 212.530,85.012 215.860,84.786 217.400 C 84.561 218.940,84.191 221.820,83.964 223.800 C 83.737 225.780,83.288 229.560,82.965 232.200 C 81.886 241.026,80.172 255.664,79.404 262.600 C 78.867 267.450,78.532 270.381,76.987 283.800 C 76.251 290.187,75.405 297.881,74.568 305.800 C 74.220 309.100,73.789 313.150,73.613 314.800 C 73.436 316.450,73.063 320.230,72.784 323.200 C 72.504 326.170,72.169 328.723,72.038 328.874 C 71.701 329.262,59.638 327.033,54.028 325.546 C 34.668 320.412,26.096 301.951,35.625 285.911 C 38.026 281.869,41.515 278.587,49.795 272.581 C 58.081 266.570,59.262 265.247,59.510 261.702 C 59.969 255.136,50.677 252.070,40.551 255.447 C -6.127 271.014,-3.894 337.227,43.806 351.951 C 50.541 354.030,58.050 355.239,67.760 355.807 C 72.410 356.079,75.202 356.542,82.181 358.199 C 88.822 359.777,100.215 360.425,156.000 362.398 C 170.725 362.918,255.192 362.921,267.760 362.401 C 273.062 362.182,281.900 361.820,287.400 361.597 C 302.851 360.972,326.558 359.339,333.200 358.444 C 343.055 357.116,343.889 354.966,341.839 336.200 C 341.502 333.120,340.948 327.900,340.607 324.600 C 340.266 321.300,339.709 315.990,339.370 312.800 C 339.030 309.610,338.499 304.570,338.189 301.600 C 337.022 290.393,335.650 278.160,334.622 269.800 C 333.105 257.460,332.638 254.027,330.408 238.800 C 329.716 234.070,328.983 229.030,328.781 227.600 C 328.579 226.170,328.231 223.920,328.008 222.600 C 327.785 221.280,326.695 214.260,325.587 207.000 C 324.478 199.740,323.124 191.010,322.578 187.600 C 322.032 184.190,321.325 179.780,321.007 177.800 C 320.689 175.820,320.203 172.711,319.925 170.892 C 319.508 168.155,319.315 167.635,318.810 167.885 C 318.475 168.051,314.780 168.279,310.600 168.393 C 301.870 168.631,302.159 168.535,301.810 171.300 C 299.468 189.825,283.036 203.371,264.230 202.279 C 247.552 201.310,233.532 188.465,231.203 172.020 C 230.651 168.125,232.337 168.400,209.000 168.400 C 185.703 168.400,187.432 168.114,186.814 172.064 C 180.639 211.474,123.556 212.329,116.559 173.117 C 115.684 168.218,116.787 168.629,103.881 168.400 C 97.676 168.290,92.285 168.046,91.900 167.857 C 91.307 167.567,91.200 167.712,91.200 168.809 M211.015 197.632 C 214.247 200.942,215.394 201.357,220.447 201.050 C 225.236 200.759,225.846 201.071,224.310 203.023 C 221.899 206.089,216.333 205.843,210.779 202.425 C 208.312 200.907,207.846 200.906,205.600 202.405 C 200.180 206.022,193.561 206.136,191.600 202.647 C 190.824 201.267,191.555 200.665,193.600 201.001 C 199.643 201.993,201.561 201.450,204.900 197.805 C 207.534 194.929,208.352 194.906,211.015 197.632 "
|
||||
stroke="none" fill="url(#Gradient2)" fill-rule="evenodd"></path>
|
||||
<path id="path1"
|
||||
d="M148.000 131.622 C 132.020 133.140,119.114 145.293,116.377 161.400 C 115.675 165.535,116.697 165.239,103.579 165.112 C 97.252 165.050,92.159 165.135,92.261 165.300 C 92.364 165.465,92.279 165.600,92.074 165.600 C 91.391 165.600,91.684 167.617,92.424 168.013 C 92.839 168.235,97.730 168.400,103.897 168.400 C 116.551 168.400,115.666 168.070,116.562 173.117 C 123.522 212.326,180.639 211.470,186.814 172.064 C 187.432 168.114,185.703 168.400,209.000 168.400 C 232.337 168.400,230.651 168.125,231.203 172.020 C 233.532 188.465,247.552 201.310,264.230 202.279 C 283.039 203.371,299.468 189.826,301.811 171.294 C 302.169 168.458,302.345 168.400,310.600 168.400 C 318.988 168.400,319.609 168.159,318.852 165.200 C 318.824 165.090,315.273 165.052,310.961 165.117 C 301.855 165.252,302.274 165.421,301.620 161.367 C 295.239 121.807,237.531 121.949,231.235 161.540 C 231.013 162.937,230.622 164.332,230.367 164.640 C 229.717 165.423,188.328 165.481,187.689 164.700 C 187.463 164.425,186.981 162.602,186.617 160.650 C 183.194 142.288,166.648 129.850,148.000 131.622 M159.886 135.622 C 183.880 141.759,192.035 172.033,174.435 189.636 C 156.404 207.671,125.892 198.962,119.944 174.084 C 114.368 150.761,136.343 129.601,159.886 135.622 M274.658 135.615 C 299.082 141.861,307.061 172.817,288.734 190.222 C 267.975 209.936,234.188 195.420,234.219 166.800 C 234.241 145.502,253.935 130.315,274.658 135.615 M148.542 152.793 C 139.499 154.706,134.598 164.925,138.715 173.287 C 145.082 186.221,164.875 182.425,165.902 168.074 C 166.591 158.446,157.916 150.811,148.542 152.793 M262.091 153.188 C 253.922 156.127,249.883 165.408,253.408 173.139 C 257.835 182.850,271.593 184.491,278.201 176.097 C 287.389 164.426,275.974 148.192,262.091 153.188 M204.900 197.805 C 201.561 201.450,199.643 201.993,193.600 201.001 C 191.555 200.665,190.824 201.267,191.600 202.647 C 193.561 206.136,200.180 206.022,205.600 202.405 C 207.846 200.906,208.312 200.907,210.779 202.425 C 216.333 205.843,221.899 206.089,224.310 203.023 C 225.846 201.071,225.236 200.759,220.447 201.050 C 215.394 201.357,214.247 200.942,211.015 197.632 C 208.352 194.906,207.534 194.929,204.900 197.805 "
|
||||
stroke="none" fill="#ffffff" fill-rule="evenodd"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 60 KiB |