Compare commits
102 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26abe7e7d7 | ||
|
|
b9c86ed3a1 | ||
|
|
b7cff66a80 | ||
|
|
61a40d2860 | ||
|
|
80eb569366 | ||
|
|
54fe669d89 | ||
|
|
0953237e9e | ||
|
|
cf1a8599eb | ||
|
|
171132be12 | ||
|
|
43c95422b7 | ||
|
|
2662243641 | ||
|
|
060a35e091 | ||
|
|
de1132c2df | ||
|
|
f19edc9370 | ||
|
|
f1601c463b | ||
|
|
77b15cd530 | ||
|
|
a6479fe0d0 | ||
|
|
4ad4e27dc1 | ||
|
|
7370684985 | ||
|
|
5ae58e6a98 | ||
|
|
780ccb1932 | ||
|
|
6b4076be10 | ||
|
|
d7a04a15ae | ||
|
|
2ae43f8bdb | ||
|
|
d3ebc17a10 | ||
|
|
7a8680711e | ||
|
|
649e89e7af | ||
|
|
cb94d64395 | ||
|
|
2440dc2440 | ||
|
|
364a24c580 | ||
|
|
8f3e0dbd82 | ||
|
|
596234df26 | ||
|
|
c38aec50dc | ||
|
|
40915b5f98 | ||
|
|
a176613119 | ||
|
|
6c6de1ae7f | ||
|
|
edbd168dcf | ||
|
|
127858d582 | ||
|
|
baf90cfbdd | ||
|
|
1a5eeb9401 | ||
|
|
e0ae101ff4 | ||
|
|
8b4a07dfe8 | ||
|
|
db934e70cb | ||
|
|
b770048f05 | ||
|
|
27c53be209 | ||
|
|
d93c12b354 | ||
|
|
98d4a47efb | ||
|
|
8ab04c65b5 | ||
|
|
1b2dab1388 | ||
|
|
4f8dae7fa0 | ||
|
|
cdc23e32c4 | ||
|
|
20457e9e63 | ||
|
|
e63042af84 | ||
|
|
c35b4d3c1b | ||
|
|
64a83a5d64 | ||
|
|
01039d0b47 | ||
|
|
7c1e5a3cba | ||
|
|
038161527f | ||
|
|
b12b7a17e6 | ||
|
|
37cf23d5fe | ||
|
|
ed7fb4f6e3 | ||
|
|
5d4bd2fee6 | ||
|
|
aae5906311 | ||
|
|
4a7bafd011 | ||
|
|
626ebfe65d | ||
|
|
3cc75cd46d | ||
|
|
f809ee7b20 | ||
|
|
1295d8191c | ||
|
|
bc2adbfa77 | ||
|
|
9583dff176 | ||
|
|
5732b84a7b | ||
|
|
c0d27504ac | ||
|
|
3db1dd7bbb | ||
|
|
5392766c5e | ||
|
|
730b7dea37 | ||
|
|
02a13ce028 | ||
|
|
7884853098 | ||
|
|
e122ea8146 | ||
|
|
f500d2b9f4 | ||
|
|
79e53bf1f5 | ||
|
|
31de7ec094 | ||
|
|
2e4501187c | ||
|
|
4430c9bd74 | ||
|
|
cf8be85ff7 | ||
|
|
0759be1223 | ||
|
|
21f8ddcf9f | ||
|
|
37cba5ee34 | ||
|
|
ff642fd1ac | ||
|
|
647f1d9c8b | ||
|
|
d886195ee3 | ||
|
|
e2b8f4f89a | ||
|
|
1dcfe661e9 | ||
|
|
d6dd110781 | ||
|
|
a0f956c885 | ||
|
|
88bcafed97 | ||
|
|
6e4f15ab52 | ||
|
|
20cae1ff4d | ||
|
|
dcf621b822 | ||
|
|
eafa20032b | ||
|
|
7375e1a490 | ||
|
|
199d87ba84 | ||
|
|
b43975ebfc |
57
.github/workflows/build-linux.yml
vendored
57
.github/workflows/build-linux.yml
vendored
@@ -1,10 +1,20 @@
|
||||
name: release Linux
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
required: false
|
||||
type: string
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
OutputArch: "linux-64"
|
||||
OutputArchArm: "linux-arm64"
|
||||
OutputPath64: "${{ github.workspace }}/v2rayN/Release/linux-64"
|
||||
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/linux-arm64"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -21,14 +31,47 @@ jobs:
|
||||
- name: Build
|
||||
run: |
|
||||
cd v2rayN
|
||||
chmod 755 build-linux.sh
|
||||
./build-linux.sh
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPath64
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPathArm64
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPath64
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: v2rayN-linux
|
||||
path: |
|
||||
./v2rayN/v2rayN-linux.zip
|
||||
${{ github.workspace }}/v2rayN/Release/linux*
|
||||
|
||||
|
||||
# release debian package
|
||||
- name: Package debian
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
chmod 755 package-debian.sh
|
||||
./package-debian.sh $OutputArch $OutputPath64 ${{ github.event.inputs.release_tag }}
|
||||
./package-debian.sh $OutputArchArm $OutputPathArm64 ${{ github.event.inputs.release_tag }}
|
||||
|
||||
- name: Upload deb to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
if: github.event.inputs.release_tag != ''
|
||||
with:
|
||||
file: ${{ github.workspace }}/v2rayN*.deb
|
||||
tag: ${{ github.event.inputs.release_tag }}
|
||||
file_glob: true
|
||||
|
||||
# release zip archive
|
||||
- name: Package release zip archive
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
chmod 755 package-release-zip.sh
|
||||
./package-release-zip.sh $OutputArch $OutputPath64
|
||||
./package-release-zip.sh $OutputArchArm $OutputPathArm64
|
||||
|
||||
- name: Upload zip archive to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
if: github.event.inputs.release_tag != ''
|
||||
with:
|
||||
file: ${{ github.workspace }}/v2rayN*.zip
|
||||
tag: ${{ github.event.inputs.release_tag }}
|
||||
file_glob: true
|
||||
prerelease: true
|
||||
60
.github/workflows/build-osx.yml
vendored
60
.github/workflows/build-osx.yml
vendored
@@ -1,10 +1,20 @@
|
||||
name: release macOS
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
required: false
|
||||
type: string
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
OutputArch: "macos-64"
|
||||
OutputArchArm: "macos-arm64"
|
||||
OutputPath64: "${{ github.workspace }}/v2rayN/Release/macos-64"
|
||||
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/macos-arm64"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -21,14 +31,48 @@ jobs:
|
||||
- name: Build
|
||||
run: |
|
||||
cd v2rayN
|
||||
chmod 755 build-osx.sh
|
||||
./build-osx.sh
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPath64
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPathArm64
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPath64
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: v2rayN-osx
|
||||
name: v2rayN-macos
|
||||
path: |
|
||||
./v2rayN/v2rayN-osx.zip
|
||||
${{ github.workspace }}/v2rayN/Release/macos*
|
||||
|
||||
# release osx package
|
||||
- name: Package osx
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
brew install create-dmg
|
||||
chmod 755 package-osx.sh
|
||||
./package-osx.sh $OutputArch $OutputPath64 ${{ github.event.inputs.release_tag }}
|
||||
./package-osx.sh $OutputArchArm $OutputPathArm64 ${{ github.event.inputs.release_tag }}
|
||||
|
||||
- name: Upload dmg to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
if: github.event.inputs.release_tag != ''
|
||||
with:
|
||||
file: ${{ github.workspace }}/v2rayN*.dmg
|
||||
tag: ${{ github.event.inputs.release_tag }}
|
||||
file_glob: true
|
||||
|
||||
|
||||
# release zip archive
|
||||
- name: Package release zip archive
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
chmod 755 package-release-zip.sh
|
||||
./package-release-zip.sh $OutputArch $OutputPath64
|
||||
./package-release-zip.sh $OutputArchArm $OutputPathArm64
|
||||
|
||||
- name: Upload zip archive to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
if: github.event.inputs.release_tag != ''
|
||||
with:
|
||||
file: ${{ github.workspace }}/v2rayN*.zip
|
||||
tag: ${{ github.event.inputs.release_tag }}
|
||||
file_glob: true
|
||||
prerelease: true
|
||||
71
.github/workflows/build-windows.yml
vendored
Normal file
71
.github/workflows/build-windows.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
name: release Windows
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
required: false
|
||||
type: string
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
OutputArch: "windows-64"
|
||||
OutputArchArm: "windows-arm64"
|
||||
OutputPath64: "${{ github.workspace }}/v2rayN/Release/windows-64"
|
||||
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/windows-arm64"
|
||||
OutputPath64Sc: "${{ github.workspace }}/v2rayN/Release/windows-64-SelfContained"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Release]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd v2rayN
|
||||
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64
|
||||
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 --self-contained false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
|
||||
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc
|
||||
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: v2rayN-windows
|
||||
path: |
|
||||
${{ github.workspace }}/v2rayN/Release/windows*
|
||||
|
||||
# release zip archive
|
||||
- name: Package release zip archive
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
chmod 755 package-release-zip.sh
|
||||
./package-release-zip.sh $OutputArch $OutputPath64
|
||||
./package-release-zip.sh $OutputArchArm $OutputPathArm64
|
||||
./package-release-zip.sh "windows-64-SelfContained" $OutputPath64Sc
|
||||
|
||||
- name: Upload zip archive to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
if: github.event.inputs.release_tag != ''
|
||||
with:
|
||||
file: ${{ github.workspace }}/v2rayN*.zip
|
||||
tag: ${{ github.event.inputs.release_tag }}
|
||||
file_glob: true
|
||||
prerelease: true
|
||||
41
.github/workflows/build.yml
vendored
41
.github/workflows/build.yml
vendored
@@ -1,41 +0,0 @@
|
||||
name: release Windows
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Release]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
run: cd v2rayN &&
|
||||
./build.ps1
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: v2rayN-windows-64
|
||||
path: |
|
||||
./v2rayN/v2rayN-windows-64.zip
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: v2rayN-windows-arm64
|
||||
path: |
|
||||
./v2rayN/v2rayN-windows-arm64.zip
|
||||
|
||||
|
||||
|
||||
|
||||
2
.github/workflows/winget-publish.yml
vendored
2
.github/workflows/winget-publish.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
$github = Invoke-RestMethod -uri "https://api.github.com/repos/2dust/v2rayN/releases"
|
||||
|
||||
$targetRelease = $github | Where-Object -Property prerelease -match 'False' | Select -First 1
|
||||
$installerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-64-With-Core\.zip*' | Select -ExpandProperty browser_download_url
|
||||
$installerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-64\.zip*' | Select -ExpandProperty browser_download_url
|
||||
|
||||
$ver = $targetRelease.tag_name
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# v2rayN
|
||||
A GUI client for Windows and Linux, support [Xray core](https://github.com/XTLS/Xray-core) and [sing-box-core](https://github.com/SagerNet/sing-box/releases) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
|
||||
A GUI client for Windows, Linux and macOS, support [Xray core](https://github.com/XTLS/Xray-core) and [sing-box-core](https://github.com/SagerNet/sing-box/releases) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
|
||||
|
||||
|
||||
[](https://github.com/2dust/v2rayN/commits/master)
|
||||
@@ -19,6 +19,11 @@ Debian 9+
|
||||
Ubuntu 16.04+
|
||||
Fedora 30+
|
||||
```
|
||||
### macOS
|
||||
- `chmod +x v2rayN` Run `./v2rayN` under user permissions
|
||||
```
|
||||
macOS 11+
|
||||
```
|
||||
|
||||
## Requirements
|
||||
- [Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
|
||||
|
||||
58
package-debian.sh
Normal file
58
package-debian.sh
Normal file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
|
||||
Arch="$1"
|
||||
OutputPath="$2"
|
||||
Version="$3"
|
||||
|
||||
FileName="v2rayN-${Arch}.zip"
|
||||
wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName"
|
||||
7z x $FileName
|
||||
cp -rf v2rayN-${Arch}/* $OutputPath
|
||||
|
||||
PackagePath="v2rayN-Package-${Arch}"
|
||||
mkdir -p "${PackagePath}/DEBIAN"
|
||||
mkdir -p "${PackagePath}/opt"
|
||||
cp -rf $OutputPath "${PackagePath}/opt/v2rayN"
|
||||
echo "When this file exists, app will not store configs under this folder" > "${PackagePath}/opt/v2rayN/NotStoreConfigHere.txt"
|
||||
|
||||
if [ $Arch = "linux-64" ]; then
|
||||
Arch2="amd64"
|
||||
else
|
||||
Arch2="arm64"
|
||||
fi
|
||||
echo $Arch2
|
||||
|
||||
# basic
|
||||
cat >"${PackagePath}/DEBIAN/control" <<-EOF
|
||||
Package: v2rayN
|
||||
Version: $Version
|
||||
Architecture: $Arch2
|
||||
Maintainer: https://github.com/2dust/v2rayN
|
||||
Description: A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||
EOF
|
||||
|
||||
cat >"${PackagePath}/DEBIAN/postinst" <<-EOF
|
||||
if [ ! -s /usr/share/applications/v2rayN.desktop ]; then
|
||||
cat >/usr/share/applications/v2rayN.desktop<<-END
|
||||
[Desktop Entry]
|
||||
Name=v2rayN
|
||||
Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||
Exec=/opt/v2rayN/v2rayN
|
||||
Icon=/opt/v2rayN/v2rayN.png
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Network;Application;
|
||||
END
|
||||
fi
|
||||
|
||||
update-desktop-database
|
||||
EOF
|
||||
|
||||
sudo chmod 0755 "${PackagePath}/DEBIAN/postinst"
|
||||
sudo chmod 0755 "${PackagePath}/opt/v2rayN/v2rayN"
|
||||
sudo chmod 0755 "${PackagePath}/opt/v2rayN/AmazTool"
|
||||
|
||||
# desktop && PATH
|
||||
|
||||
sudo dpkg-deb -Zxz --build $PackagePath
|
||||
sudo mv "${PackagePath}.deb" "v2rayN-${Arch}.deb"
|
||||
58
package-osx.sh
Executable file
58
package-osx.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
|
||||
Arch="$1"
|
||||
OutputPath="$2"
|
||||
Version="$3"
|
||||
|
||||
FileName="v2rayN-${Arch}.zip"
|
||||
wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName"
|
||||
7z x $FileName
|
||||
cp -rf v2rayN-${Arch}/* $OutputPath
|
||||
|
||||
PackagePath="v2rayN-Package-${Arch}"
|
||||
mkdir -p "$PackagePath/v2rayN.app/Contents/Resources"
|
||||
cp -rf "$OutputPath" "$PackagePath/v2rayN.app/Contents/MacOS"
|
||||
cp -f "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.icns" "$PackagePath/v2rayN.app/Contents/Resources/AppIcon.icns"
|
||||
echo "When this file exists, app will not store configs under this folder" > "$PackagePath/v2rayN.app/Contents/MacOS/NotStoreConfigHere.txt"
|
||||
chmod +x "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN"
|
||||
|
||||
cat >"$PackagePath/v2rayN.app/Contents/Info.plist" <<-EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>v2rayN</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>v2rayN</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>AppIcon</string>
|
||||
<key>CFBundleIconName</key>
|
||||
<string>AppIcon</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>2dust.v2rayN</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>v2rayN</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${Version}</string>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
create-dmg \
|
||||
--volname "v2rayN Installer" \
|
||||
--window-size 700 420 \
|
||||
--icon-size 100 \
|
||||
--icon "v2rayN.app" 160 185 \
|
||||
--hide-extension "v2rayN.app" \
|
||||
--app-drop-link 500 185 \
|
||||
"v2rayN-${Arch}.dmg" \
|
||||
"$PackagePath/v2rayN.app"
|
||||
15
package-release-zip.sh
Normal file
15
package-release-zip.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
Arch="$1"
|
||||
OutputPath="$2"
|
||||
|
||||
OutputArch="v2rayN-${Arch}"
|
||||
FileName="v2rayN-${Arch}.zip"
|
||||
|
||||
wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName"
|
||||
|
||||
ZipPath64="./$OutputArch"
|
||||
mkdir $ZipPath64
|
||||
|
||||
cp -rf $OutputPath "$ZipPath64/$OutputArch"
|
||||
7z a -tZip $FileName "$ZipPath64/$OutputArch" -mx1
|
||||
@@ -5,8 +5,8 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
|
||||
<FileVersion>1.3.0</FileVersion>
|
||||
<Copyright>Copyright © 2017-2025 (GPLv3)</Copyright>
|
||||
<FileVersion>1.3.1</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -15,8 +15,15 @@
|
||||
return;
|
||||
}
|
||||
|
||||
var fileName = Uri.UnescapeDataString(string.Join(" ", args));
|
||||
UpgradeApp.Upgrade(fileName);
|
||||
var argData = Uri.UnescapeDataString(string.Join(" ", args));
|
||||
if (argData.Equals("rebootas"))
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
Utils.StartV2RayN();
|
||||
return;
|
||||
}
|
||||
|
||||
UpgradeApp.Upgrade(argData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ namespace AmazTool
|
||||
{
|
||||
Console.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}");
|
||||
|
||||
Waiting(9);
|
||||
Utils.Waiting(5);
|
||||
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
@@ -21,11 +21,11 @@ namespace AmazTool
|
||||
Console.WriteLine(Resx.Resource.TryTerminateProcess);
|
||||
try
|
||||
{
|
||||
var existing = Process.GetProcessesByName(V2rayN);
|
||||
var existing = Process.GetProcessesByName(Utils.V2rayN);
|
||||
foreach (var pp in existing)
|
||||
{
|
||||
var path = pp.MainModule?.FileName ?? "";
|
||||
if (path.StartsWith(GetPath(V2rayN)))
|
||||
if (path.StartsWith(Utils.GetPath(Utils.V2rayN)))
|
||||
{
|
||||
pp?.Kill();
|
||||
pp?.WaitForExit(1000);
|
||||
@@ -42,12 +42,12 @@ namespace AmazTool
|
||||
StringBuilder sb = new();
|
||||
try
|
||||
{
|
||||
string thisAppOldFile = $"{GetExePath()}.tmp";
|
||||
var thisAppOldFile = $"{Utils.GetExePath()}.tmp";
|
||||
File.Delete(thisAppOldFile);
|
||||
string splitKey = "/";
|
||||
var splitKey = "/";
|
||||
|
||||
using ZipArchive archive = ZipFile.OpenRead(fileName);
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
using var archive = ZipFile.OpenRead(fileName);
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -60,15 +60,20 @@ namespace AmazTool
|
||||
|
||||
var lst = entry.FullName.Split(splitKey);
|
||||
if (lst.Length == 1) continue;
|
||||
string fullName = string.Join(splitKey, lst[1..lst.Length]);
|
||||
var fullName = string.Join(splitKey, lst[1..lst.Length]);
|
||||
|
||||
if (string.Equals(GetExePath(), GetPath(fullName), StringComparison.OrdinalIgnoreCase))
|
||||
if (string.Equals(Utils.GetExePath(), Utils.GetPath(fullName), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
File.Move(GetExePath(), thisAppOldFile);
|
||||
File.Move(Utils.GetExePath(), thisAppOldFile);
|
||||
}
|
||||
|
||||
string entryOutputPath = GetPath(fullName);
|
||||
var entryOutputPath = Utils.GetPath(fullName);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
||||
//In the bin folder, if the file already exists, it will be skipped
|
||||
if (fullName.StartsWith("bin") && File.Exists(entryOutputPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
entry.ExtractToFile(entryOutputPath, true);
|
||||
|
||||
Console.WriteLine(entryOutputPath);
|
||||
@@ -91,48 +96,9 @@ namespace AmazTool
|
||||
}
|
||||
|
||||
Console.WriteLine(Resx.Resource.Restartv2rayN);
|
||||
Waiting(9);
|
||||
Process process = new()
|
||||
{
|
||||
StartInfo = new()
|
||||
{
|
||||
UseShellExecute = true,
|
||||
FileName = V2rayN,
|
||||
WorkingDirectory = StartupPath()
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
}
|
||||
Utils.Waiting(2);
|
||||
|
||||
private static string GetExePath()
|
||||
{
|
||||
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
|
||||
Utils.StartV2RayN();
|
||||
}
|
||||
|
||||
private static string StartupPath()
|
||||
{
|
||||
return AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
|
||||
private static string GetPath(string fileName)
|
||||
{
|
||||
string startupPath = StartupPath();
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
return startupPath;
|
||||
}
|
||||
return Path.Combine(startupPath, fileName);
|
||||
}
|
||||
|
||||
private static void Waiting(int second)
|
||||
{
|
||||
for (var i = second; i > 0; i--)
|
||||
{
|
||||
Console.WriteLine(i);
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
private static string V2rayN => "v2rayN";
|
||||
}
|
||||
}
|
||||
52
v2rayN/AmazTool/Utils.cs
Normal file
52
v2rayN/AmazTool/Utils.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace AmazTool
|
||||
{
|
||||
internal class Utils
|
||||
{
|
||||
public static string GetExePath()
|
||||
{
|
||||
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
|
||||
}
|
||||
|
||||
public static string StartupPath()
|
||||
{
|
||||
return AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
|
||||
public static string GetPath(string fileName)
|
||||
{
|
||||
string startupPath = StartupPath();
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
return startupPath;
|
||||
}
|
||||
return Path.Combine(startupPath, fileName);
|
||||
}
|
||||
|
||||
public static string V2rayN => "v2rayN";
|
||||
|
||||
public static void StartV2RayN()
|
||||
{
|
||||
Process process = new()
|
||||
{
|
||||
StartInfo = new()
|
||||
{
|
||||
UseShellExecute = true,
|
||||
FileName = V2rayN,
|
||||
WorkingDirectory = StartupPath()
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
}
|
||||
|
||||
public static void Waiting(int second)
|
||||
{
|
||||
for (var i = second; i > 0; i--)
|
||||
{
|
||||
Console.WriteLine(i);
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ namespace ServiceLib.Common
|
||||
{
|
||||
public static class FileManager
|
||||
{
|
||||
private static readonly string _tag = "FileManager";
|
||||
|
||||
public static bool ByteArrayToFile(string fileName, byte[] content)
|
||||
{
|
||||
try
|
||||
@@ -15,7 +17,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -30,7 +32,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +48,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +62,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +81,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -105,13 +107,13 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -130,7 +132,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -148,13 +150,13 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive, string? ignoredName)
|
||||
public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive, bool overwrite, string? ignoredName = null)
|
||||
{
|
||||
// Get information about the source directory
|
||||
var dir = new DirectoryInfo(sourceDir);
|
||||
@@ -181,7 +183,11 @@ namespace ServiceLib.Common
|
||||
continue;
|
||||
}
|
||||
var targetFilePath = Path.Combine(destinationDir, file.Name);
|
||||
file.CopyTo(targetFilePath, true);
|
||||
if (!overwrite && File.Exists(targetFilePath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
file.CopyTo(targetFilePath, overwrite);
|
||||
}
|
||||
|
||||
// If recursive and copying subdirectories, recursively call this method
|
||||
@@ -190,9 +196,30 @@ namespace ServiceLib.Common
|
||||
foreach (var subDir in dirs)
|
||||
{
|
||||
var newDestinationDir = Path.Combine(destinationDir, subDir.Name);
|
||||
CopyDirectory(subDir.FullName, newDestinationDir, true, ignoredName);
|
||||
CopyDirectory(subDir.FullName, newDestinationDir, true, overwrite, ignoredName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DeleteExpiredFiles(string sourceDir, DateTime dtLine)
|
||||
{
|
||||
try
|
||||
{
|
||||
var files = Directory.GetFiles(sourceDir, "*.*");
|
||||
foreach (var filePath in files)
|
||||
{
|
||||
var file = new FileInfo(filePath);
|
||||
if (file.CreationTime >= dtLine)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
file.Delete();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ namespace ServiceLib.Common
|
||||
{
|
||||
public class JsonUtils
|
||||
{
|
||||
private static readonly string _tag = "JsonUtils";
|
||||
|
||||
/// <summary>
|
||||
/// DeepCopy
|
||||
/// </summary>
|
||||
@@ -90,7 +92,31 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serialize Object to Json string
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
public static string Serialize(object? obj, JsonSerializerOptions options)
|
||||
{
|
||||
var result = string.Empty;
|
||||
try
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result = JsonSerializer.Serialize(obj, options);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -25,36 +25,6 @@ namespace ServiceLib.Common
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearLogs()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var now = DateTime.Now.AddMonths(-1);
|
||||
var dir = Utils.GetLogPath();
|
||||
var files = Directory.GetFiles(dir, "*.txt");
|
||||
foreach (var filePath in files)
|
||||
{
|
||||
var file = new FileInfo(filePath);
|
||||
if (file.CreationTime >= now) continue;
|
||||
try
|
||||
{
|
||||
file.Delete();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void SaveLog(string strContent)
|
||||
{
|
||||
if (!LogManager.IsLoggingEnabled()) return;
|
||||
|
||||
139
v2rayN/ServiceLib/Common/ProcUtils.cs
Normal file
139
v2rayN/ServiceLib/Common/ProcUtils.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace ServiceLib.Common;
|
||||
|
||||
public static class ProcUtils
|
||||
{
|
||||
private static readonly string _tag = "ProcUtils";
|
||||
|
||||
public static void ProcessStart(string? fileName, string arguments = "")
|
||||
{
|
||||
ProcessStart(fileName, arguments, null);
|
||||
}
|
||||
|
||||
public static int? ProcessStart(string? fileName, string arguments, string? dir)
|
||||
{
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (fileName.Contains(' ')) fileName = fileName.AppendQuotes();
|
||||
if (arguments.Contains(' ')) arguments = arguments.AppendQuotes();
|
||||
|
||||
Process process = new()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
UseShellExecute = true,
|
||||
FileName = fileName,
|
||||
Arguments = arguments,
|
||||
WorkingDirectory = dir
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
return process.Id;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void RebootAsAdmin(bool blAdmin = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessStartInfo startInfo = new()
|
||||
{
|
||||
UseShellExecute = true,
|
||||
Arguments = Global.RebootAs,
|
||||
WorkingDirectory = Utils.StartupPath(),
|
||||
FileName = Utils.GetExePath().AppendQuotes(),
|
||||
Verb = blAdmin ? "runas" : null,
|
||||
};
|
||||
Process.Start(startInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task ProcessKill(int pid)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ProcessKill(Process.GetProcessById(pid), false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task ProcessKill(Process? proc, bool review)
|
||||
{
|
||||
if (proc is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GetProcessKeyInfo(proc, review, out var procId, out var fileName, out var processName);
|
||||
|
||||
try { proc?.Kill(true); } catch (Exception ex) { Logging.SaveLog(_tag, ex); }
|
||||
try { proc?.Kill(); } catch (Exception ex) { Logging.SaveLog(_tag, ex); }
|
||||
try { proc?.Close(); } catch (Exception ex) { Logging.SaveLog(_tag, ex); }
|
||||
try { proc?.Dispose(); } catch (Exception ex) { Logging.SaveLog(_tag, ex); }
|
||||
|
||||
await Task.Delay(300);
|
||||
await ProcessKillByKeyInfo(review, procId, fileName, processName);
|
||||
}
|
||||
|
||||
private static void GetProcessKeyInfo(Process? proc, bool review, out int? procId, out string? fileName, out string? processName)
|
||||
{
|
||||
procId = null;
|
||||
fileName = null;
|
||||
processName = null;
|
||||
if (!review) return;
|
||||
try
|
||||
{
|
||||
procId = proc?.Id;
|
||||
fileName = proc?.MainModule?.FileName;
|
||||
processName = proc?.ProcessName;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task ProcessKillByKeyInfo(bool review, int? procId, string? fileName, string? processName)
|
||||
{
|
||||
if (review && procId != null && fileName != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var lstProc = Process.GetProcessesByName(processName);
|
||||
foreach (var proc2 in lstProc)
|
||||
{
|
||||
if (proc2.Id == procId)
|
||||
{
|
||||
Logging.SaveLog($"{_tag}, KillProcess not completing the job, procId");
|
||||
await ProcessKill(proc2, false);
|
||||
}
|
||||
if (proc2.MainModule != null && proc2.MainModule?.FileName == fileName)
|
||||
{
|
||||
Logging.SaveLog($"{_tag}, KillProcess not completing the job, fileName");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,5 +73,19 @@ namespace ServiceLib.Common
|
||||
{
|
||||
return _dbAsync.Table<T>();
|
||||
}
|
||||
|
||||
public async Task DisposeDbConnectionAsync()
|
||||
{
|
||||
await Task.Factory.StartNew(() =>
|
||||
{
|
||||
_db?.Close();
|
||||
_db?.Dispose();
|
||||
_db = null;
|
||||
|
||||
_dbAsync?.GetConnection()?.Close();
|
||||
_dbAsync?.GetConnection()?.Dispose();
|
||||
_dbAsync = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@ namespace ServiceLib.Common
|
||||
{
|
||||
public class Utils
|
||||
{
|
||||
private static readonly string _tag = "Utils";
|
||||
|
||||
#region 资源操作
|
||||
|
||||
/// <summary>
|
||||
@@ -36,7 +38,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -57,7 +59,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -92,7 +94,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
@@ -117,7 +119,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -139,7 +141,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -159,7 +161,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("Base64Encode", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
@@ -193,7 +195,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("Base64Decode", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
@@ -483,7 +485,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -515,10 +517,10 @@ namespace ServiceLib.Common
|
||||
|
||||
#region 杂项
|
||||
|
||||
public static bool UpgradeAppExists(out string fileName)
|
||||
public static bool UpgradeAppExists(out string upgradeFileName)
|
||||
{
|
||||
fileName = Path.Combine(Utils.StartupPath(), GetExeName("AmazTool"));
|
||||
return File.Exists(fileName);
|
||||
upgradeFileName = Path.Combine(GetBaseDirectory(), GetExeName("AmazTool"));
|
||||
return File.Exists(upgradeFileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -530,12 +532,12 @@ namespace ServiceLib.Common
|
||||
try
|
||||
{
|
||||
return blFull
|
||||
? $"{Global.AppName} - V{GetVersionInfo()} - {RuntimeInformation.ProcessArchitecture} - {StartupPath()}"
|
||||
? $"{Global.AppName} - V{GetVersionInfo()} - {RuntimeInformation.ProcessArchitecture}"
|
||||
: $"{Global.AppName}/{GetVersionInfo()}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return Global.AppName;
|
||||
@@ -549,11 +551,16 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return "0.0";
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetRuntimeInfo()
|
||||
{
|
||||
return $"{Utils.GetVersion()} | {Utils.StartupPath()} | {Utils.GetExePath()} | {Environment.OSVersion}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取得GUID
|
||||
/// </summary>
|
||||
@@ -573,7 +580,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
@@ -584,23 +591,6 @@ namespace ServiceLib.Common
|
||||
return Guid.TryParse(strSrc, out _);
|
||||
}
|
||||
|
||||
public static void ProcessStart(string? fileName, string arguments = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Process.Start(new ProcessStartInfo(fileName, arguments) { UseShellExecute = true });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<string, string> GetSystemHosts()
|
||||
{
|
||||
var systemHosts = new Dictionary<string, string>();
|
||||
@@ -623,7 +613,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return systemHosts;
|
||||
@@ -675,7 +665,13 @@ namespace ServiceLib.Common
|
||||
{
|
||||
try
|
||||
{
|
||||
var tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "guiTemps");
|
||||
//When this file exists, it is equivalent to having no permission to read and write
|
||||
if (File.Exists(Path.Combine(GetBaseDirectory(), "NotStoreConfigHere.txt")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var tempPath = Path.Combine(GetBaseDirectory(), "guiTemps");
|
||||
if (!Directory.Exists(tempPath))
|
||||
{
|
||||
Directory.CreateDirectory(tempPath);
|
||||
@@ -703,6 +699,11 @@ namespace ServiceLib.Common
|
||||
return Path.Combine(startupPath, fileName);
|
||||
}
|
||||
|
||||
public static string GetBaseDirectory(string fileName = "")
|
||||
{
|
||||
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
|
||||
}
|
||||
|
||||
public static string GetExePath()
|
||||
{
|
||||
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
|
||||
@@ -710,12 +711,12 @@ namespace ServiceLib.Common
|
||||
|
||||
public static string StartupPath()
|
||||
{
|
||||
if (Utils.IsNonWindows() && Environment.GetEnvironmentVariable("V2RAYN_LOCAL_APPLICATION_DATA") == "1")
|
||||
if (Environment.GetEnvironmentVariable(Global.LocalAppData) == "1")
|
||||
{
|
||||
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "v2rayN");
|
||||
}
|
||||
|
||||
return AppDomain.CurrentDomain.BaseDirectory;
|
||||
return GetBaseDirectory();
|
||||
}
|
||||
|
||||
public static string GetTempPath(string filename = "")
|
||||
@@ -851,18 +852,19 @@ namespace ServiceLib.Common
|
||||
{
|
||||
return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
|
||||
}
|
||||
else
|
||||
{
|
||||
var id = GetLinuxUserId().Result ?? "1000";
|
||||
if (int.TryParse(id, out var userId))
|
||||
{
|
||||
return userId == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
//else
|
||||
//{
|
||||
// var id = GetLinuxUserId().Result ?? "1000";
|
||||
// if (int.TryParse(id, out var userId))
|
||||
// {
|
||||
// return userId == 0;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
private static async Task<string?> GetLinuxUserId()
|
||||
@@ -874,6 +876,7 @@ namespace ServiceLib.Common
|
||||
public static async Task<string?> SetLinuxChmod(string? fileName)
|
||||
{
|
||||
if (fileName.IsNullOrEmpty()) return null;
|
||||
if (fileName.Contains(' ')) fileName = fileName.AppendQuotes();
|
||||
//File.SetUnixFileMode(fileName, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute);
|
||||
var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
|
||||
return await GetCliWrapOutput("/bin/bash", arg);
|
||||
@@ -893,6 +896,12 @@ namespace ServiceLib.Common
|
||||
: Environment.GetEnvironmentVariable("HOME");
|
||||
}
|
||||
|
||||
public static async Task<string?> GetListNetworkServices()
|
||||
{
|
||||
var arg = new List<string>() { "-c", $"networksetup -listallnetworkservices" };
|
||||
return await GetCliWrapOutput("/bin/bash", arg);
|
||||
}
|
||||
|
||||
#endregion Platform
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ namespace ServiceLib.Common
|
||||
{
|
||||
internal static class WindowsUtils
|
||||
{
|
||||
private static readonly string _tag = "WindowsUtils";
|
||||
|
||||
public static string? RegReadValue(string path, string name, string def)
|
||||
{
|
||||
RegistryKey? regKey = null;
|
||||
@@ -15,7 +17,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -41,7 +43,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace ServiceLib.Common
|
||||
{
|
||||
public class YamlUtils
|
||||
{
|
||||
private static readonly string _tag = "YamlUtils";
|
||||
|
||||
#region YAML
|
||||
|
||||
/// <summary>
|
||||
@@ -26,7 +28,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("FromYaml", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return deserializer.Deserialize<T>("");
|
||||
}
|
||||
}
|
||||
@@ -53,7 +55,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -71,7 +73,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("PreprocessYaml", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
{
|
||||
Default = 0,
|
||||
Russia = 1,
|
||||
Iran = 2,
|
||||
}
|
||||
}
|
||||
13
v2rayN/ServiceLib/Enums/ETheme.cs
Normal file
13
v2rayN/ServiceLib/Enums/ETheme.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace ServiceLib.Enums
|
||||
{
|
||||
public enum ETheme
|
||||
{
|
||||
FollowSystem,
|
||||
Dark,
|
||||
Light,
|
||||
Aquatic,
|
||||
Desert,
|
||||
Dusk,
|
||||
NightSky
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@
|
||||
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
|
||||
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
||||
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
|
||||
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
||||
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
|
||||
public const string IPAPIUrl = "https://api.ip.sb/geoip";
|
||||
|
||||
@@ -63,13 +62,13 @@
|
||||
public const string HttpProtocol = "http://";
|
||||
public const string HttpsProtocol = "https://";
|
||||
public const string SocksProtocol = "socks://";
|
||||
public const string Socks5Protocol = "socks5://";
|
||||
|
||||
public const string UserEMail = "t@t.tt";
|
||||
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||
public const string AutoRunName = "v2rayNAutoRun";
|
||||
public const string CustomIconName = "v2rayN.ico";
|
||||
public const string SystemProxyExceptionsWindows = "localhost;127.*;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.*;192.168.*";
|
||||
public const string SystemProxyExceptionsLinux = "localhost, 127.0.0.0/8, ::1";
|
||||
public const string SystemProxyExceptionsLinux = "localhost,127.0.0.0/8,::1";
|
||||
public const string RoutingRuleComma = "<COMMA>";
|
||||
public const string GrpcGunMode = "gun";
|
||||
public const string GrpcMultiMode = "multi";
|
||||
@@ -79,67 +78,82 @@
|
||||
public const int MinFontSize = 8;
|
||||
public const string RebootAs = "rebootas";
|
||||
public const string AvaAssets = "avares://v2rayN/Assets/";
|
||||
public const string LocalAppData = "V2RAYN_LOCAL_APPLICATION_DATA";
|
||||
public const string V2RayLocalAsset = "V2RAY_LOCATION_ASSET";
|
||||
public const string XrayLocalAsset = "XRAY_LOCATION_ASSET";
|
||||
|
||||
public static readonly List<string> IEProxyProtocols = new() {
|
||||
"{ip}:{http_port}",
|
||||
"socks={ip}:{socks_port}",
|
||||
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
|
||||
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
|
||||
""
|
||||
};
|
||||
public static readonly List<string> IEProxyProtocols =
|
||||
[
|
||||
"{ip}:{http_port}",
|
||||
"socks={ip}:{socks_port}",
|
||||
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
|
||||
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
|
||||
""
|
||||
];
|
||||
|
||||
public static readonly List<string> SubConvertUrls = new List<string> {
|
||||
@"https://sub.xeton.dev/sub?url={0}",
|
||||
@"https://api.dler.io/sub?url={0}",
|
||||
@"http://127.0.0.1:25500/sub?url={0}",
|
||||
""
|
||||
};
|
||||
public static readonly List<string> SubConvertUrls =
|
||||
[
|
||||
@"https://sub.xeton.dev/sub?url={0}",
|
||||
@"https://api.dler.io/sub?url={0}",
|
||||
@"http://127.0.0.1:25500/sub?url={0}",
|
||||
""
|
||||
];
|
||||
|
||||
public static readonly List<string> SubConvertConfig = new List<string> {
|
||||
@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"
|
||||
};
|
||||
public static readonly List<string> SubConvertConfig =
|
||||
[@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"];
|
||||
|
||||
public static readonly List<string> SubConvertTargets = new List<string> {
|
||||
"",
|
||||
"mixed",
|
||||
"v2ray",
|
||||
"clash",
|
||||
"ss",
|
||||
};
|
||||
public static readonly List<string> SubConvertTargets =
|
||||
[
|
||||
"",
|
||||
"mixed",
|
||||
"v2ray",
|
||||
"clash",
|
||||
"ss"
|
||||
];
|
||||
|
||||
public static readonly List<string> SpeedTestUrls = new() {
|
||||
public static readonly List<string> SpeedTestUrls =
|
||||
[
|
||||
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
||||
@"https://speed.cloudflare.com/__down?bytes=50000000",
|
||||
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
||||
@"https://cachefly.cachefly.net/50mb.test",
|
||||
};
|
||||
@"https://cachefly.cachefly.net/50mb.test"
|
||||
];
|
||||
|
||||
public static readonly List<string> SpeedPingTestUrls = new() {
|
||||
public static readonly List<string> SpeedPingTestUrls =
|
||||
[
|
||||
@"https://www.google.com/generate_204",
|
||||
@"https://www.gstatic.com/generate_204",
|
||||
@"https://www.apple.com/library/test/success.html",
|
||||
@"http://www.msftconnecttest.com/connecttest.txt",
|
||||
};
|
||||
@"http://www.msftconnecttest.com/connecttest.txt"
|
||||
];
|
||||
|
||||
public static readonly List<string> GeoFilesSources = new() {
|
||||
public static readonly List<string> GeoFilesSources =
|
||||
[
|
||||
"",
|
||||
@"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat",
|
||||
};
|
||||
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-v2ray-rules@release/{0}.dat"
|
||||
];
|
||||
|
||||
public static readonly List<string> SingboxRulesetSources = new() {
|
||||
public static readonly List<string> SingboxRulesetSources =
|
||||
[
|
||||
"",
|
||||
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-rules-dat@release/sing-box/rule-set-{0}/{1}.srs",
|
||||
};
|
||||
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-sing-box-rules@rule-set/{1}.srs"
|
||||
];
|
||||
|
||||
public static readonly List<string> RoutingRulesSources = new() {
|
||||
public static readonly List<string> RoutingRulesSources =
|
||||
[
|
||||
"",
|
||||
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/template.json",
|
||||
};
|
||||
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/template.json"
|
||||
];
|
||||
|
||||
public static readonly List<string> DNSTemplateSources = new() {
|
||||
public static readonly List<string> DNSTemplateSources =
|
||||
[
|
||||
"",
|
||||
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/",
|
||||
};
|
||||
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/"
|
||||
];
|
||||
|
||||
public static readonly Dictionary<string, string> UserAgentTexts = new()
|
||||
{
|
||||
@@ -177,42 +191,314 @@
|
||||
{EConfigType.WireGuard,"wireguard"}
|
||||
};
|
||||
|
||||
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
|
||||
public static readonly List<string> SsSecurities = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
|
||||
public static readonly List<string> SsSecuritiesInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
|
||||
public static readonly List<string> SsSecuritiesInSingbox = new() { "aes-256-gcm", "aes-192-gcm", "aes-128-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20" };
|
||||
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
||||
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "xhttp", "h2", "quic", "grpc" };
|
||||
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
||||
public static readonly List<string> CoreTypes = new() { "Xray", "sing_box" };
|
||||
public static readonly List<string> DomainStrategies = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
|
||||
public static readonly List<string> DomainStrategies4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
|
||||
public static readonly List<string> DomainMatchers = new() { "linear", "mph", "" };
|
||||
public static readonly List<string> Fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
|
||||
public static readonly List<string> UserAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
|
||||
public static readonly List<string> XhttpMode = new() { "auto", "packet-up", "stream-up", "stream-one" };
|
||||
public static readonly List<string> VmessSecurities =
|
||||
[
|
||||
"aes-128-gcm",
|
||||
"chacha20-poly1305",
|
||||
"auto",
|
||||
"none",
|
||||
"zero"
|
||||
];
|
||||
|
||||
public static readonly List<string> AllowInsecure = new() { "true", "false", "" };
|
||||
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
|
||||
public static readonly List<string> SingboxDomainStrategy4Out = new() { "ipv4_only", "prefer_ipv4", "prefer_ipv6", "ipv6_only", "" };
|
||||
public static readonly List<string> DomainDNSAddress = ["223.5.5.5", "223.6.6.6", "localhost"];
|
||||
public static readonly List<string> SingboxDomainDNSAddress = ["223.5.5.5", "223.6.6.6", "dhcp://auto"];
|
||||
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru", "hu" };
|
||||
public static readonly List<string> Alpns = new() { "h3", "h2", "http/1.1", "h3,h2", "h2,http/1.1", "h3,h2,http/1.1", "" };
|
||||
public static readonly List<string> LogLevels = new() { "debug", "info", "warning", "error", "none" };
|
||||
public static readonly List<string> InboundTags = new() { "socks", "socks2", "socks3" };
|
||||
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
|
||||
public static readonly List<string> RuleNetworks = new() { "", "tcp", "udp", "tcp,udp" };
|
||||
public static readonly List<string> destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"];
|
||||
public static readonly List<string> TunMtus = new() { "1280", "1408", "1500", "9000" };
|
||||
public static readonly List<string> TunStacks = new() { "gvisor", "system" };
|
||||
public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
|
||||
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
|
||||
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
|
||||
public static readonly List<string> SsSecurities =
|
||||
[
|
||||
"aes-256-gcm",
|
||||
"aes-128-gcm",
|
||||
"chacha20-poly1305",
|
||||
"chacha20-ietf-poly1305",
|
||||
"none",
|
||||
"plain"
|
||||
];
|
||||
|
||||
public static readonly List<string> allowSelectType = new() { "selector", "urltest", "loadbalance", "fallback" };
|
||||
public static readonly List<string> notAllowTestType = new() { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
|
||||
public static readonly List<string> proxyVehicleType = new() { "file", "http" };
|
||||
public static readonly List<string> SsSecuritiesInXray =
|
||||
[
|
||||
"aes-256-gcm",
|
||||
"aes-128-gcm",
|
||||
"chacha20-poly1305",
|
||||
"chacha20-ietf-poly1305",
|
||||
"xchacha20-poly1305",
|
||||
"xchacha20-ietf-poly1305",
|
||||
"none",
|
||||
"plain",
|
||||
"2022-blake3-aes-128-gcm",
|
||||
"2022-blake3-aes-256-gcm",
|
||||
"2022-blake3-chacha20-poly1305"
|
||||
];
|
||||
|
||||
public static readonly List<string> SsSecuritiesInSingbox =
|
||||
[
|
||||
"aes-256-gcm",
|
||||
"aes-192-gcm",
|
||||
"aes-128-gcm",
|
||||
"chacha20-ietf-poly1305",
|
||||
"xchacha20-ietf-poly1305",
|
||||
"none",
|
||||
"2022-blake3-aes-128-gcm",
|
||||
"2022-blake3-aes-256-gcm",
|
||||
"2022-blake3-chacha20-poly1305",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"rc4-md5",
|
||||
"chacha20-ietf",
|
||||
"xchacha20"
|
||||
];
|
||||
|
||||
public static readonly List<string> Flows =
|
||||
[
|
||||
"",
|
||||
"xtls-rprx-vision",
|
||||
"xtls-rprx-vision-udp443"
|
||||
];
|
||||
|
||||
public static readonly List<string> Networks =
|
||||
[
|
||||
"tcp",
|
||||
"kcp",
|
||||
"ws",
|
||||
"httpupgrade",
|
||||
"xhttp",
|
||||
"h2",
|
||||
"quic",
|
||||
"grpc"
|
||||
];
|
||||
|
||||
public static readonly List<string> KcpHeaderTypes =
|
||||
[
|
||||
"srtp",
|
||||
"utp",
|
||||
"wechat-video",
|
||||
"dtls",
|
||||
"wireguard"
|
||||
];
|
||||
|
||||
public static readonly List<string> CoreTypes =
|
||||
[
|
||||
"Xray",
|
||||
"sing_box"
|
||||
];
|
||||
|
||||
public static readonly List<string> DomainStrategies =
|
||||
[
|
||||
"AsIs",
|
||||
"IPIfNonMatch",
|
||||
"IPOnDemand"
|
||||
];
|
||||
|
||||
public static readonly List<string> DomainStrategies4Singbox =
|
||||
[
|
||||
"ipv4_only",
|
||||
"ipv6_only",
|
||||
"prefer_ipv4",
|
||||
"prefer_ipv6",
|
||||
""
|
||||
];
|
||||
|
||||
public static readonly List<string> DomainMatchers =
|
||||
[
|
||||
"linear",
|
||||
"mph",
|
||||
""
|
||||
];
|
||||
|
||||
public static readonly List<string> Fingerprints =
|
||||
[
|
||||
"chrome",
|
||||
"firefox",
|
||||
"safari",
|
||||
"ios",
|
||||
"android",
|
||||
"edge",
|
||||
"360",
|
||||
"qq",
|
||||
"random",
|
||||
"randomized",
|
||||
""
|
||||
];
|
||||
|
||||
public static readonly List<string> UserAgent =
|
||||
[
|
||||
"chrome",
|
||||
"firefox",
|
||||
"safari",
|
||||
"edge",
|
||||
"none"
|
||||
];
|
||||
|
||||
public static readonly List<string> XhttpMode =
|
||||
[
|
||||
"auto",
|
||||
"packet-up",
|
||||
"stream-up",
|
||||
"stream-one"
|
||||
];
|
||||
|
||||
public static readonly List<string> AllowInsecure =
|
||||
[
|
||||
"true",
|
||||
"false",
|
||||
""
|
||||
];
|
||||
|
||||
public static readonly List<string> DomainStrategy4Freedoms =
|
||||
[
|
||||
"AsIs",
|
||||
"UseIP",
|
||||
"UseIPv4",
|
||||
"UseIPv6",
|
||||
""
|
||||
];
|
||||
|
||||
public static readonly List<string> SingboxDomainStrategy4Out =
|
||||
[
|
||||
"ipv4_only",
|
||||
"prefer_ipv4",
|
||||
"prefer_ipv6",
|
||||
"ipv6_only",
|
||||
""
|
||||
];
|
||||
|
||||
public static readonly List<string> DomainDNSAddress =
|
||||
[
|
||||
"223.5.5.5",
|
||||
"223.6.6.6",
|
||||
"localhost"
|
||||
];
|
||||
|
||||
public static readonly List<string> SingboxDomainDNSAddress =
|
||||
[
|
||||
"223.5.5.5",
|
||||
"223.6.6.6",
|
||||
"dhcp://auto"
|
||||
];
|
||||
|
||||
public static readonly List<string> Languages =
|
||||
[
|
||||
"zh-Hans",
|
||||
"zh-Hant",
|
||||
"en",
|
||||
"fa-Ir",
|
||||
"ru",
|
||||
"hu"
|
||||
];
|
||||
|
||||
public static readonly List<string> Alpns =
|
||||
[
|
||||
"h3",
|
||||
"h2",
|
||||
"http/1.1",
|
||||
"h3,h2",
|
||||
"h2,http/1.1",
|
||||
"h3,h2,http/1.1",
|
||||
""
|
||||
];
|
||||
|
||||
public static readonly List<string> LogLevels =
|
||||
[
|
||||
"debug",
|
||||
"info",
|
||||
"warning",
|
||||
"error",
|
||||
"none"
|
||||
];
|
||||
|
||||
public static readonly List<string> InboundTags =
|
||||
[
|
||||
"socks",
|
||||
"socks2",
|
||||
"socks3"
|
||||
];
|
||||
|
||||
public static readonly List<string> RuleProtocols =
|
||||
[
|
||||
"http",
|
||||
"tls",
|
||||
"bittorrent"
|
||||
];
|
||||
|
||||
public static readonly List<string> RuleNetworks =
|
||||
[
|
||||
"",
|
||||
"tcp",
|
||||
"udp",
|
||||
"tcp,udp"
|
||||
];
|
||||
|
||||
public static readonly List<string> destOverrideProtocols =
|
||||
[
|
||||
"http",
|
||||
"tls",
|
||||
"quic",
|
||||
"fakedns",
|
||||
"fakedns+others"
|
||||
];
|
||||
|
||||
public static readonly List<string> TunMtus =
|
||||
[
|
||||
"1280",
|
||||
"1408",
|
||||
"1500",
|
||||
"9000"
|
||||
];
|
||||
|
||||
public static readonly List<string> TunStacks =
|
||||
[
|
||||
"gvisor",
|
||||
"system",
|
||||
"mixed"
|
||||
];
|
||||
|
||||
public static readonly List<string> PresetMsgFilters =
|
||||
[
|
||||
"proxy",
|
||||
"direct",
|
||||
"block",
|
||||
""
|
||||
];
|
||||
|
||||
public static readonly List<string> SingboxMuxs =
|
||||
[
|
||||
"h2mux",
|
||||
"smux",
|
||||
"yamux",
|
||||
""
|
||||
];
|
||||
|
||||
public static readonly List<string> TuicCongestionControls =
|
||||
[
|
||||
"cubic",
|
||||
"new_reno",
|
||||
"bbr"
|
||||
];
|
||||
|
||||
public static readonly List<string> allowSelectType =
|
||||
[
|
||||
"selector",
|
||||
"urltest",
|
||||
"loadbalance",
|
||||
"fallback"
|
||||
];
|
||||
|
||||
public static readonly List<string> notAllowTestType =
|
||||
[
|
||||
"selector",
|
||||
"urltest",
|
||||
"direct",
|
||||
"reject",
|
||||
"compatible",
|
||||
"pass",
|
||||
"loadbalance",
|
||||
"fallback"
|
||||
];
|
||||
|
||||
public static readonly List<string> proxyVehicleType =
|
||||
[
|
||||
"file",
|
||||
"http"
|
||||
];
|
||||
|
||||
#endregion const
|
||||
}
|
||||
|
||||
@@ -46,9 +46,9 @@
|
||||
|
||||
public bool InitApp()
|
||||
{
|
||||
if (Utils.IsNonWindows() && Utils.HasWritePermission() == false)
|
||||
if (Utils.HasWritePermission() == false)
|
||||
{
|
||||
Environment.SetEnvironmentVariable("V2RAYN_LOCAL_APPLICATION_DATA", "1", EnvironmentVariableTarget.Process);
|
||||
Environment.SetEnvironmentVariable(Global.LocalAppData, "1", EnvironmentVariableTarget.Process);
|
||||
}
|
||||
|
||||
Logging.Setup();
|
||||
@@ -77,10 +77,10 @@
|
||||
|
||||
public bool InitComponents()
|
||||
{
|
||||
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
||||
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||
Logging.SaveLog($"v2rayN start up | {Utils.GetRuntimeInfo()}");
|
||||
Logging.LoggingEnabled(_config.GuiItem.EnableLog);
|
||||
Logging.ClearLogs();
|
||||
|
||||
ClearExpiredFiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -92,6 +92,15 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ClearExpiredFiles()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1));
|
||||
FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Config
|
||||
@@ -107,7 +116,13 @@
|
||||
if (Utils.IsWindows())
|
||||
{
|
||||
_processJob ??= new();
|
||||
_processJob?.AddProcess(processHandle);
|
||||
try
|
||||
{
|
||||
_processJob?.AddProcess(processHandle);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +135,7 @@
|
||||
return await SQLiteHelper.Instance.TableAsync<SubItem>().OrderBy(t => t.Sort).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<SubItem?> GetSubItem(string subid)
|
||||
public async Task<SubItem?> GetSubItem(string? subid)
|
||||
{
|
||||
return await SQLiteHelper.Instance.TableAsync<SubItem>().FirstOrDefaultAsync(t => t.Id == subid);
|
||||
}
|
||||
@@ -165,45 +180,6 @@
|
||||
return await SQLiteHelper.Instance.QueryAsync<ProfileItemModel>(sql);
|
||||
}
|
||||
|
||||
public async Task<List<ProfileItemModel>?> ProfileItemsEx(string subid, string filter)
|
||||
{
|
||||
var lstModel = await ProfileItems(_config.SubIndexId, filter);
|
||||
|
||||
await ConfigHandler.SetDefaultServer(_config, lstModel);
|
||||
|
||||
var lstServerStat = (_config.GuiItem.EnableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
|
||||
var lstProfileExs = await ProfileExHandler.Instance.GetProfileExs();
|
||||
lstModel = (from t in lstModel
|
||||
join t2 in lstServerStat on t.IndexId equals t2.IndexId into t2b
|
||||
from t22 in t2b.DefaultIfEmpty()
|
||||
join t3 in lstProfileExs on t.IndexId equals t3.IndexId into t3b
|
||||
from t33 in t3b.DefaultIfEmpty()
|
||||
select new ProfileItemModel
|
||||
{
|
||||
IndexId = t.IndexId,
|
||||
ConfigType = t.ConfigType,
|
||||
Remarks = t.Remarks,
|
||||
Address = t.Address,
|
||||
Port = t.Port,
|
||||
Security = t.Security,
|
||||
Network = t.Network,
|
||||
StreamSecurity = t.StreamSecurity,
|
||||
Subid = t.Subid,
|
||||
SubRemarks = t.SubRemarks,
|
||||
IsActive = t.IndexId == _config.IndexId,
|
||||
Sort = t33 == null ? 0 : t33.Sort,
|
||||
Delay = t33 == null ? 0 : t33.Delay,
|
||||
DelayVal = t33?.Delay != 0 ? $"{t33?.Delay} {Global.DelayUnit}" : string.Empty,
|
||||
SpeedVal = t33?.Speed != 0 ? $"{t33?.Speed} {Global.SpeedUnit}" : string.Empty,
|
||||
TodayDown = t22 == null ? "" : Utils.HumanFy(t22.TodayDown),
|
||||
TodayUp = t22 == null ? "" : Utils.HumanFy(t22.TodayUp),
|
||||
TotalDown = t22 == null ? "" : Utils.HumanFy(t22.TotalDown),
|
||||
TotalUp = t22 == null ? "" : Utils.HumanFy(t22.TotalUp)
|
||||
}).OrderBy(t => t.Sort).ToList();
|
||||
|
||||
return lstModel;
|
||||
}
|
||||
|
||||
public async Task<ProfileItem?> GetProfileItem(string indexId)
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(indexId))
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
public static class AutoStartupHandler
|
||||
{
|
||||
private static readonly string _tag = "AutoStartupHandler";
|
||||
|
||||
public static async Task<bool> UpdateTask(Config config)
|
||||
{
|
||||
if (Utils.IsWindows())
|
||||
@@ -43,6 +45,8 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
AutoStartTaskService(autoRunName, "", "");
|
||||
}
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static async Task SetTaskWindows()
|
||||
@@ -62,8 +66,9 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -123,8 +128,9 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static async Task SetTaskLinux()
|
||||
@@ -143,7 +149,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace ServiceLib.Handler
|
||||
|
||||
private Dictionary<string, ProxiesItem>? _proxies;
|
||||
public Dictionary<string, object> ProfileContent { get; set; }
|
||||
private static readonly string _tag = "ClashApiHandler";
|
||||
|
||||
public async Task<Tuple<ClashProxies, ClashProviders>?> GetClashProxiesAsync(Config config)
|
||||
{
|
||||
@@ -109,7 +110,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("GetClashProxyGroups", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -125,7 +126,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +154,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +170,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -184,7 +185,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace ServiceLib.Handler
|
||||
public class ConfigHandler
|
||||
{
|
||||
private static readonly string _configRes = Global.ConfigFileName;
|
||||
private static readonly string _tag = "ConfigHandler";
|
||||
|
||||
#region ConfigHandler
|
||||
|
||||
@@ -68,7 +69,7 @@ namespace ServiceLib.Handler
|
||||
config.RoutingBasicItem ??= new();
|
||||
if (Utils.IsNullOrEmpty(config.RoutingBasicItem.DomainStrategy))
|
||||
{
|
||||
config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies.First();//"IPIfNonMatch";
|
||||
config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies.First();
|
||||
}
|
||||
|
||||
config.KcpItem ??= new KcpItem
|
||||
@@ -93,10 +94,7 @@ namespace ServiceLib.Handler
|
||||
EnableTun = false,
|
||||
Mtu = 9000,
|
||||
};
|
||||
config.GuiItem ??= new()
|
||||
{
|
||||
EnableStatistics = false,
|
||||
};
|
||||
config.GuiItem ??= new();
|
||||
config.MsgUIItem ??= new();
|
||||
|
||||
config.UiItem ??= new UIItem()
|
||||
@@ -155,12 +153,13 @@ namespace ServiceLib.Handler
|
||||
config.SystemProxyItem ??= new();
|
||||
config.WebDavItem ??= new();
|
||||
config.CheckUpdateItem ??= new();
|
||||
|
||||
if (Utils.IsNotEmpty(config.ConstItem.DefIEProxyExceptions))
|
||||
config.Fragment4RayItem ??= new()
|
||||
{
|
||||
config.SystemProxyItem.SystemProxyExceptions = $"{config.ConstItem.DefIEProxyExceptions};{config.SystemProxyItem.SystemProxyExceptions}";
|
||||
config.ConstItem.DefIEProxyExceptions = string.Empty;
|
||||
}
|
||||
Packets = "tlshello",
|
||||
Length = "100-200",
|
||||
Interval = "10-20"
|
||||
};
|
||||
|
||||
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
|
||||
{
|
||||
config.SystemProxyItem.SystemProxyExceptions = Utils.IsWindows() ? Global.SystemProxyExceptionsWindows : Global.SystemProxyExceptionsLinux;
|
||||
@@ -194,7 +193,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("ToJsonFile", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -470,7 +469,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
|
||||
ProfileExHandler.Instance.SetSort(lstProfile[index].IndexId, sort);
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -500,7 +499,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -987,7 +986,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("Remove Item", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1048,7 +1047,7 @@ namespace ServiceLib.Handler
|
||||
Port = node.PreSocksPort.Value,
|
||||
};
|
||||
}
|
||||
|
||||
await Task.CompletedTask;
|
||||
return itemSocks;
|
||||
}
|
||||
|
||||
@@ -1618,7 +1617,7 @@ namespace ServiceLib.Handler
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
public static async Task<int> SetDefaultRouting(Config config, RoutingItem routingItem)
|
||||
@@ -1868,6 +1867,16 @@ namespace ServiceLib.Handler
|
||||
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[1] + "v2ray.json"));
|
||||
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[1] + "sing_box.json"));
|
||||
|
||||
return true;
|
||||
|
||||
case EPresetType.Iran:
|
||||
config.ConstItem.GeoSourceUrl = Global.GeoFilesSources[2];
|
||||
config.ConstItem.SrsSourceUrl = Global.SingboxRulesetSources[2];
|
||||
config.ConstItem.RouteRulesTemplateSourceUrl = Global.RoutingRulesSources[2];
|
||||
|
||||
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[2] + "v2ray.json"));
|
||||
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[2] + "sing_box.json"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
/// </summary>
|
||||
public class CoreConfigHandler
|
||||
{
|
||||
private static readonly string _tag = "CoreConfigHandler";
|
||||
|
||||
public static async Task<RetResult> GenerateClientConfig(ProfileItem node, string? fileName)
|
||||
{
|
||||
var config = AppHandler.Instance.Config;
|
||||
@@ -78,11 +80,11 @@
|
||||
|
||||
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||
ret.Success = true;
|
||||
return ret;
|
||||
return await Task.FromResult(ret);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("GenerateClientCustomConfig", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -15,14 +15,26 @@ namespace ServiceLib.Handler
|
||||
private Process? _processPre;
|
||||
private int _linuxSudoPid = -1;
|
||||
private Action<bool, string>? _updateFunc;
|
||||
private const string _tag = "CoreHandler";
|
||||
|
||||
public async Task Init(Config config, Action<bool, string> updateFunc)
|
||||
{
|
||||
_config = config;
|
||||
_updateFunc = updateFunc;
|
||||
|
||||
Environment.SetEnvironmentVariable("V2RAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
Environment.SetEnvironmentVariable("XRAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
Environment.SetEnvironmentVariable(Global.V2RayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
Environment.SetEnvironmentVariable(Global.XrayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
|
||||
//Copy the bin folder to the storage location (for init)
|
||||
if (Environment.GetEnvironmentVariable(Global.LocalAppData) == "1")
|
||||
{
|
||||
var fromPath = Utils.GetBaseDirectory("bin");
|
||||
var toPath = Utils.GetBinPath("");
|
||||
if (fromPath != toPath)
|
||||
{
|
||||
FileManager.CopyDirectory(fromPath, toPath, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (Utils.IsNonWindows())
|
||||
{
|
||||
@@ -31,9 +43,9 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
if (it.CoreType == ECoreType.v2rayN)
|
||||
{
|
||||
if (Utils.UpgradeAppExists(out var fileName))
|
||||
if (Utils.UpgradeAppExists(out var upgradeFileName))
|
||||
{
|
||||
await Utils.SetLinuxChmod(fileName);
|
||||
await Utils.SetLinuxChmod(upgradeFileName);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -54,7 +66,7 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
ShowMsg(false, ResUI.CheckServerSettings);
|
||||
UpdateFunc(false, ResUI.CheckServerSettings);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -62,17 +74,21 @@ namespace ServiceLib.Handler
|
||||
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
|
||||
if (result.Success != true)
|
||||
{
|
||||
ShowMsg(true, result.Msg);
|
||||
UpdateFunc(true, result.Msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ShowMsg(true, $"{node.GetSummary()}");
|
||||
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||
UpdateFunc(false, $"{node.GetSummary()}");
|
||||
UpdateFunc(false, $"{Utils.GetRuntimeInfo()}");
|
||||
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||
await CoreStop();
|
||||
await Task.Delay(100);
|
||||
await CoreStart(node);
|
||||
await CoreStartPreService(node);
|
||||
if (_process != null)
|
||||
{
|
||||
UpdateFunc(true, $"{node.GetSummary()}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
||||
@@ -80,15 +96,23 @@ namespace ServiceLib.Handler
|
||||
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
|
||||
var configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
|
||||
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
||||
ShowMsg(false, result.Msg);
|
||||
UpdateFunc(false, result.Msg);
|
||||
if (result.Success != true)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||
ShowMsg(false, configPath);
|
||||
return await CoreStartSpeedtest(configPath, coreType);
|
||||
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||
UpdateFunc(false, configPath);
|
||||
|
||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
||||
var proc = await RunProcess(coreInfo, Global.CoreSpeedtestConfigFileName, true, false);
|
||||
if (proc is null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return proc.Id;
|
||||
}
|
||||
|
||||
public async Task CoreStop()
|
||||
@@ -97,12 +121,14 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
if (_process != null)
|
||||
{
|
||||
_process = await KillProcess(_process);
|
||||
await ProcUtils.ProcessKill(_process, true);
|
||||
_process = null;
|
||||
}
|
||||
|
||||
if (_processPre != null)
|
||||
{
|
||||
_processPre = await KillProcess(_processPre);
|
||||
await ProcUtils.ProcessKill(_processPre, true);
|
||||
_processPre = null;
|
||||
}
|
||||
|
||||
if (_linuxSudoPid > 0)
|
||||
@@ -113,45 +139,12 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CoreStopPid(int pid)
|
||||
{
|
||||
try
|
||||
{
|
||||
await KillProcess(Process.GetProcessById(pid));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
#region Private
|
||||
|
||||
private string CoreFindExe(CoreInfo coreInfo)
|
||||
{
|
||||
var fileName = string.Empty;
|
||||
foreach (var name in coreInfo.CoreExes)
|
||||
{
|
||||
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
|
||||
if (File.Exists(vName))
|
||||
{
|
||||
fileName = vName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(fileName))
|
||||
{
|
||||
var msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.CoreType.ToString()), string.Join(", ", coreInfo.CoreExes.ToArray()), coreInfo.Url);
|
||||
Logging.SaveLog(msg);
|
||||
ShowMsg(false, msg);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private async Task CoreStart(ProfileItem node)
|
||||
{
|
||||
var coreType = _config.RunningCoreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
|
||||
@@ -191,28 +184,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<int> CoreStartSpeedtest(string configPath, ECoreType coreType)
|
||||
{
|
||||
try
|
||||
{
|
||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
||||
var proc = await RunProcess(coreInfo, Global.CoreSpeedtestConfigFileName, true, false);
|
||||
if (proc is null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return proc.Id;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
ShowMsg(false, ex.Message);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowMsg(bool notify, string msg)
|
||||
private void UpdateFunc(bool notify, string msg)
|
||||
{
|
||||
_updateFunc?.Invoke(notify, msg);
|
||||
}
|
||||
@@ -230,11 +202,12 @@ namespace ServiceLib.Handler
|
||||
|
||||
#region Process
|
||||
|
||||
private async Task<Process?> RunProcess(CoreInfo coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
|
||||
private async Task<Process?> RunProcess(CoreInfo? coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
|
||||
{
|
||||
var fileName = CoreFindExe(coreInfo);
|
||||
var fileName = CoreInfoHandler.Instance.GetCoreExecFile(coreInfo, out var msg);
|
||||
if (Utils.IsNullOrEmpty(fileName))
|
||||
{
|
||||
UpdateFunc(false, msg);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -262,24 +235,17 @@ namespace ServiceLib.Handler
|
||||
await RunProcessAsLinuxSudo(proc, fileName, coreInfo, configPath);
|
||||
}
|
||||
|
||||
var startUpErrorMessage = new StringBuilder();
|
||||
var startUpSuccessful = false;
|
||||
if (displayLog)
|
||||
{
|
||||
proc.OutputDataReceived += (sender, e) =>
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(e.Data)) return;
|
||||
ShowMsg(false, e.Data + Environment.NewLine);
|
||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
||||
};
|
||||
proc.ErrorDataReceived += (sender, e) =>
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(e.Data)) return;
|
||||
ShowMsg(false, e.Data + Environment.NewLine);
|
||||
|
||||
if (!startUpSuccessful)
|
||||
{
|
||||
startUpErrorMessage.Append(e.Data + Environment.NewLine);
|
||||
}
|
||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
||||
};
|
||||
}
|
||||
proc.Start();
|
||||
@@ -300,41 +266,22 @@ namespace ServiceLib.Handler
|
||||
proc.BeginErrorReadLine();
|
||||
}
|
||||
|
||||
if (proc.WaitForExit(1000))
|
||||
{
|
||||
proc.CancelErrorRead();
|
||||
throw new Exception(displayLog ? startUpErrorMessage.ToString() : "启动进程失败并退出 (Failed to start the process and exited)");
|
||||
}
|
||||
else
|
||||
{
|
||||
startUpSuccessful = true;
|
||||
}
|
||||
|
||||
await Task.Delay(500);
|
||||
AppHandler.Instance.AddProcess(proc.Handle);
|
||||
if (proc is null or { HasExited: true })
|
||||
{
|
||||
throw new Exception(ResUI.FailedToRunCore);
|
||||
}
|
||||
return proc;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
ShowMsg(true, ex.Message);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
UpdateFunc(true, ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Process?> KillProcess(Process? proc)
|
||||
{
|
||||
if (proc is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try { proc?.Kill(true); } catch { }
|
||||
try { proc?.Close(); } catch { }
|
||||
try { proc?.Dispose(); } catch { }
|
||||
|
||||
await Task.Delay(100);
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion Process
|
||||
|
||||
#region Linux
|
||||
|
||||
@@ -29,146 +29,169 @@
|
||||
return _coreInfo ?? [];
|
||||
}
|
||||
|
||||
public string GetCoreExecFile(CoreInfo? coreInfo, out string msg)
|
||||
{
|
||||
var fileName = string.Empty;
|
||||
msg = string.Empty;
|
||||
foreach (var name in coreInfo?.CoreExes)
|
||||
{
|
||||
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
|
||||
if (File.Exists(vName))
|
||||
{
|
||||
fileName = vName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.CoreType.ToString()), string.Join(", ", coreInfo.CoreExes.ToArray()), coreInfo.Url);
|
||||
Logging.SaveLog(msg);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private void InitCoreInfo()
|
||||
{
|
||||
_coreInfo = [];
|
||||
_coreInfo =
|
||||
[
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.v2rayN,
|
||||
Url = Global.NUrl,
|
||||
ReleaseApiUrl = Global.NUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
DownloadUrlWin64 = Global.NUrl + "/download/{0}/v2rayN-windows-64.zip",
|
||||
DownloadUrlWinArm64 = Global.NUrl + "/download/{0}/v2rayN-windows-arm64.zip",
|
||||
DownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip",
|
||||
DownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip",
|
||||
DownloadUrlOSX64 = Global.NUrl + "/download/{0}/v2rayN-macos-64.zip",
|
||||
DownloadUrlOSXArm64 = Global.NUrl + "/download/{0}/v2rayN-macos-arm64.zip",
|
||||
},
|
||||
|
||||
_coreInfo.Add(new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.v2rayN,
|
||||
Url = Global.NUrl,
|
||||
ReleaseApiUrl = Global.NUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
DownloadUrlWin64 = Global.NUrl + "/download/{0}/v2rayN-windows-64.zip",
|
||||
DownloadUrlWinArm64 = Global.NUrl + "/download/{0}/v2rayN-windows-arm64.zip",
|
||||
DownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip",
|
||||
DownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip",
|
||||
DownloadUrlOSX64 = Global.NUrl + "/download/{0}/v2rayN-macos-64.zip",
|
||||
DownloadUrlOSXArm64 = Global.NUrl + "/download/{0}/v2rayN-macos-arm64.zip",
|
||||
});
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.v2fly,
|
||||
CoreExes = ["wv2ray", "v2ray"],
|
||||
Arguments = "",
|
||||
Url = Global.V2flyCoreUrl,
|
||||
ReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
Match = "V2Ray",
|
||||
VersionArg = "-version",
|
||||
RedirectInfo = true,
|
||||
},
|
||||
|
||||
_coreInfo.Add(new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.v2fly,
|
||||
CoreExes = new List<string> { "wv2ray", "v2ray" },
|
||||
Arguments = "",
|
||||
Url = Global.V2flyCoreUrl,
|
||||
ReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
Match = "V2Ray",
|
||||
VersionArg = "-version",
|
||||
RedirectInfo = true,
|
||||
});
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.v2fly_v5,
|
||||
CoreExes = ["v2ray"],
|
||||
Arguments = "run -c config.json -format jsonv5",
|
||||
Url = Global.V2flyCoreUrl,
|
||||
ReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
Match = "V2Ray",
|
||||
VersionArg = "version",
|
||||
RedirectInfo = true,
|
||||
},
|
||||
|
||||
_coreInfo.Add(new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.v2fly_v5,
|
||||
CoreExes = new List<string> { "v2ray" },
|
||||
Arguments = "run -c config.json -format jsonv5",
|
||||
Url = Global.V2flyCoreUrl,
|
||||
ReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
Match = "V2Ray",
|
||||
VersionArg = "version",
|
||||
RedirectInfo = true,
|
||||
});
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.Xray,
|
||||
CoreExes = ["xray", "wxray"],
|
||||
Arguments = "run -c {0}",
|
||||
Url = Global.XrayCoreUrl,
|
||||
ReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
DownloadUrlWin64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
|
||||
DownloadUrlWinArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
|
||||
DownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip",
|
||||
DownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip",
|
||||
DownloadUrlOSX64 = Global.XrayCoreUrl + "/download/{0}/Xray-macos-64.zip",
|
||||
DownloadUrlOSXArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-macos-arm64-v8a.zip",
|
||||
Match = "Xray",
|
||||
VersionArg = "-version",
|
||||
RedirectInfo = true,
|
||||
},
|
||||
|
||||
_coreInfo.Add(new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.Xray,
|
||||
CoreExes = new List<string> { "xray", "wxray" },
|
||||
Arguments = "run -c {0}",
|
||||
Url = Global.XrayCoreUrl,
|
||||
ReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
DownloadUrlWin64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
|
||||
DownloadUrlWinArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
|
||||
DownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip",
|
||||
DownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip",
|
||||
DownloadUrlOSX64 = Global.XrayCoreUrl + "/download/{0}/Xray-macos-64.zip",
|
||||
DownloadUrlOSXArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-macos-arm64-v8a.zip",
|
||||
Match = "Xray",
|
||||
VersionArg = "-version",
|
||||
RedirectInfo = true,
|
||||
});
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.mihomo,
|
||||
CoreExes = ["mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-linux-amd64", "mihomo", "clash"],
|
||||
Arguments = "-f config.json" + PortableMode(),
|
||||
Url = Global.MihomoCoreUrl,
|
||||
ReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
DownloadUrlWin64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip",
|
||||
DownloadUrlWinArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip",
|
||||
DownloadUrlLinux64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
|
||||
DownloadUrlLinuxArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz",
|
||||
DownloadUrlOSX64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-darwin-amd64-compatible-{0}.gz",
|
||||
DownloadUrlOSXArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-darwin-arm64-{0}.gz",
|
||||
Match = "Mihomo",
|
||||
VersionArg = "-v",
|
||||
RedirectInfo = true,
|
||||
},
|
||||
|
||||
_coreInfo.Add(new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.mihomo,
|
||||
CoreExes = new List<string> { "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-linux-amd64", "mihomo", "clash" },
|
||||
Arguments = "-f config.json" + PortableMode(),
|
||||
Url = Global.MihomoCoreUrl,
|
||||
ReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
DownloadUrlWin64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip",
|
||||
DownloadUrlWinArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip",
|
||||
DownloadUrlLinux64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
|
||||
DownloadUrlLinuxArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz",
|
||||
DownloadUrlOSX64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-darwin-amd64-compatible-{0}.gz",
|
||||
DownloadUrlOSXArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-darwin-arm64-{0}.gz",
|
||||
Match = "Mihomo",
|
||||
VersionArg = "-v",
|
||||
RedirectInfo = true,
|
||||
});
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.hysteria,
|
||||
CoreExes = ["hysteria-windows-amd64", "hysteria"],
|
||||
Arguments = "",
|
||||
Url = Global.HysteriaCoreUrl,
|
||||
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
RedirectInfo = true,
|
||||
},
|
||||
|
||||
_coreInfo.Add(new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.hysteria,
|
||||
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria" },
|
||||
Arguments = "",
|
||||
Url = Global.HysteriaCoreUrl,
|
||||
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
RedirectInfo = true,
|
||||
});
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.naiveproxy,
|
||||
CoreExes = ["naiveproxy", "naive"],
|
||||
Arguments = "config.json",
|
||||
Url = Global.NaiveproxyCoreUrl,
|
||||
RedirectInfo = false,
|
||||
},
|
||||
|
||||
_coreInfo.Add(new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.naiveproxy,
|
||||
CoreExes = new List<string> { "naiveproxy", "naive" },
|
||||
Arguments = "config.json",
|
||||
Url = Global.NaiveproxyCoreUrl,
|
||||
RedirectInfo = false,
|
||||
});
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.tuic,
|
||||
CoreExes = ["tuic-client", "tuic"],
|
||||
Arguments = "-c config.json",
|
||||
Url = Global.TuicCoreUrl,
|
||||
RedirectInfo = true,
|
||||
},
|
||||
|
||||
_coreInfo.Add(new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.tuic,
|
||||
CoreExes = new List<string> { "tuic-client", "tuic" },
|
||||
Arguments = "-c config.json",
|
||||
Url = Global.TuicCoreUrl,
|
||||
RedirectInfo = true,
|
||||
});
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.sing_box,
|
||||
CoreExes = ["sing-box-client", "sing-box"],
|
||||
Arguments = "run -c {0} --disable-color",
|
||||
Url = Global.SingboxCoreUrl,
|
||||
RedirectInfo = true,
|
||||
ReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
DownloadUrlWin64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip",
|
||||
DownloadUrlWinArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
|
||||
DownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
|
||||
DownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
|
||||
DownloadUrlOSX64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-darwin-amd64.tar.gz",
|
||||
DownloadUrlOSXArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-darwin-arm64.tar.gz",
|
||||
Match = "sing-box",
|
||||
VersionArg = "version",
|
||||
},
|
||||
|
||||
_coreInfo.Add(new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.sing_box,
|
||||
CoreExes = new List<string> { "sing-box-client", "sing-box" },
|
||||
Arguments = "run -c {0} --disable-color",
|
||||
Url = Global.SingboxCoreUrl,
|
||||
RedirectInfo = true,
|
||||
ReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
DownloadUrlWin64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip",
|
||||
DownloadUrlWinArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
|
||||
DownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
|
||||
DownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
|
||||
DownloadUrlOSX64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-darwin-amd64.tar.gz",
|
||||
DownloadUrlOSXArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-darwin-arm64.tar.gz",
|
||||
Match = "sing-box",
|
||||
VersionArg = "version",
|
||||
});
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.juicity,
|
||||
CoreExes = ["juicity-client", "juicity"],
|
||||
Arguments = "run -c config.json",
|
||||
Url = Global.JuicityCoreUrl
|
||||
},
|
||||
|
||||
_coreInfo.Add(new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.juicity,
|
||||
CoreExes = new List<string> { "juicity-client", "juicity" },
|
||||
Arguments = "run -c config.json",
|
||||
Url = Global.JuicityCoreUrl
|
||||
});
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.hysteria2,
|
||||
CoreExes = ["hysteria-windows-amd64", "hysteria-linux-amd64", "hysteria"],
|
||||
Arguments = "",
|
||||
Url = Global.HysteriaCoreUrl,
|
||||
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
RedirectInfo = true,
|
||||
}
|
||||
|
||||
_coreInfo.Add(new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.hysteria2,
|
||||
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-linux-amd64", "hysteria" },
|
||||
Arguments = "",
|
||||
Url = Global.HysteriaCoreUrl,
|
||||
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||
RedirectInfo = true,
|
||||
});
|
||||
];
|
||||
}
|
||||
|
||||
private string PortableMode()
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
{
|
||||
public class FmtHandler
|
||||
{
|
||||
private static readonly string _tag = "FmtHandler";
|
||||
|
||||
public static string? GetShareUri(ProfileItem item)
|
||||
{
|
||||
try
|
||||
@@ -23,7 +25,7 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -81,7 +83,7 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
msg = ResUI.Incorrectconfiguration;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace ServiceLib.Handler
|
||||
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
|
||||
private Queue<string> _queIndexIds = new();
|
||||
public static ProfileExHandler Instance => _instance.Value;
|
||||
private static readonly string _tag = "ProfileExHandler";
|
||||
|
||||
public ProfileExHandler()
|
||||
{
|
||||
@@ -19,7 +20,7 @@ namespace ServiceLib.Handler
|
||||
public async Task Init()
|
||||
{
|
||||
await InitData();
|
||||
Task.Run(async () =>
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
@@ -31,7 +32,7 @@ namespace ServiceLib.Handler
|
||||
|
||||
public async Task<ConcurrentBag<ProfileExItem>> GetProfileExs()
|
||||
{
|
||||
return _lstProfileEx;
|
||||
return await Task.FromResult(_lstProfileEx);
|
||||
}
|
||||
|
||||
private async Task InitData()
|
||||
@@ -87,7 +88,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("ProfileExHandler", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,7 +120,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,22 +12,20 @@
|
||||
|
||||
private StatisticsXrayService? _statisticsXray;
|
||||
private StatisticsSingboxService? _statisticsSingbox;
|
||||
|
||||
private static readonly string _tag = "StatisticsHandler";
|
||||
public List<ServerStatItem> ServerStat => _lstServerStat;
|
||||
|
||||
public async Task Init(Config config, Action<ServerSpeedItem> updateFunc)
|
||||
{
|
||||
_config = config;
|
||||
_updateFunc = updateFunc;
|
||||
if (!config.GuiItem.EnableStatistics)
|
||||
if (config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
|
||||
{
|
||||
return;
|
||||
await InitData();
|
||||
|
||||
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
|
||||
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
|
||||
}
|
||||
|
||||
await InitData();
|
||||
|
||||
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
|
||||
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
@@ -39,7 +37,7 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +59,7 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +70,11 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (indexId == toIndexId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var stat = _lstServerStat.FirstOrDefault(t => t.IndexId == indexId);
|
||||
if (stat == null)
|
||||
{
|
||||
@@ -96,7 +99,7 @@
|
||||
|
||||
private void UpdateServerStatHandler(ServerSpeedItem server)
|
||||
{
|
||||
UpdateServerStat(server);
|
||||
_ = UpdateServerStat(server);
|
||||
}
|
||||
|
||||
private async Task UpdateServerStat(ServerSpeedItem server)
|
||||
|
||||
@@ -2,14 +2,10 @@
|
||||
{
|
||||
public class ProxySettingOSX
|
||||
{
|
||||
/*
|
||||
* 仅测试了,MacOS 13.7.1 x86 版本,其他版本有待确认
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// 应用接口类型
|
||||
/// </summary>
|
||||
private static readonly List<string> LstInterface = ["Ethernet", "Wi-Fi", "Thunderbolt Bridge"];
|
||||
private static readonly List<string> LstInterface = ["Ethernet", "Wi-Fi", "Thunderbolt Bridge", "USB 10/100/1000 LAN"];
|
||||
|
||||
/// <summary>
|
||||
/// 代理类型,对应 http,https,socks
|
||||
@@ -18,13 +14,15 @@
|
||||
|
||||
public static async Task SetProxy(string host, int port, string exceptions)
|
||||
{
|
||||
var lstCmd = GetSetCmds(host, port, exceptions);
|
||||
var lstInterface = await GetListNetworkServices();
|
||||
var lstCmd = GetSetCmds(lstInterface, host, port, exceptions);
|
||||
await ExecCmd(lstCmd);
|
||||
}
|
||||
|
||||
public static async Task UnsetProxy()
|
||||
{
|
||||
var lstCmd = GetUnsetCmds();
|
||||
var lstInterface = await GetListNetworkServices();
|
||||
var lstCmd = GetUnsetCmds(lstInterface);
|
||||
await ExecCmd(lstCmd);
|
||||
}
|
||||
|
||||
@@ -42,10 +40,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
private static List<CmdItem> GetSetCmds(string host, int port, string exceptions)
|
||||
private static List<CmdItem> GetSetCmds(List<string> lstInterface, string host, int port, string exceptions)
|
||||
{
|
||||
List<CmdItem> lstCmd = [];
|
||||
foreach (var interf in LstInterface)
|
||||
foreach (var interf in lstInterface)
|
||||
{
|
||||
foreach (var type in LstTypes)
|
||||
{
|
||||
@@ -70,10 +68,10 @@
|
||||
return lstCmd;
|
||||
}
|
||||
|
||||
private static List<CmdItem> GetUnsetCmds()
|
||||
private static List<CmdItem> GetUnsetCmds(List<string> lstInterface)
|
||||
{
|
||||
List<CmdItem> lstCmd = [];
|
||||
foreach (var interf in LstInterface)
|
||||
foreach (var interf in lstInterface)
|
||||
{
|
||||
foreach (var type in LstTypes)
|
||||
{
|
||||
@@ -87,5 +85,17 @@
|
||||
|
||||
return lstCmd;
|
||||
}
|
||||
|
||||
public static async Task<List<string>> GetListNetworkServices()
|
||||
{
|
||||
var services = await Utils.GetListNetworkServices();
|
||||
if (services.IsNullOrEmpty())
|
||||
{
|
||||
return LstInterface;
|
||||
}
|
||||
|
||||
var lst = services.Split(Environment.NewLine).Where(t => t.Length > 0 && t.Contains('*') == false);
|
||||
return lst.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,6 @@ namespace ServiceLib.Handler.SysProxy
|
||||
catch (Exception ex)
|
||||
{
|
||||
SetProxyFallback(strProxy, exceptions, type);
|
||||
//Logging.SaveLog(ex.Message, ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
{
|
||||
public static class SysProxyHandler
|
||||
{
|
||||
private static readonly string _tag = "SysProxyHandler";
|
||||
|
||||
public static async Task<bool> UpdateSysProxy(Config config, bool forceDisable)
|
||||
{
|
||||
var type = config.SystemProxyItem.SysProxyType;
|
||||
@@ -14,7 +16,7 @@
|
||||
try
|
||||
{
|
||||
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||
var exceptions = config.SystemProxyItem.SystemProxyExceptions;
|
||||
var exceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
|
||||
if (port <= 0)
|
||||
{
|
||||
return false;
|
||||
@@ -59,14 +61,14 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void GetWindowsProxyString(Config config, int port, out string strProxy, out string strExceptions)
|
||||
{
|
||||
strExceptions = config.SystemProxyItem.SystemProxyExceptions;
|
||||
strExceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
|
||||
if (config.SystemProxyItem.NotProxyLocalAddress)
|
||||
{
|
||||
strExceptions = $"<local>;{strExceptions}";
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace ServiceLib.Handler
|
||||
private string? _lastDescription;
|
||||
private string _webDir = Global.AppName + "_backup";
|
||||
private readonly string _webFileName = "backup.zip";
|
||||
private string _logTitle = "WebDav--";
|
||||
private readonly string _tag = "WebDav--";
|
||||
|
||||
public WebDavHandler()
|
||||
{
|
||||
@@ -81,13 +81,13 @@ namespace ServiceLib.Handler
|
||||
private void SaveLog(string desc)
|
||||
{
|
||||
_lastDescription = desc;
|
||||
Logging.SaveLog(_logTitle + desc);
|
||||
Logging.SaveLog(_tag + desc);
|
||||
}
|
||||
|
||||
private void SaveLog(Exception ex)
|
||||
{
|
||||
_lastDescription = ex.Message;
|
||||
Logging.SaveLog(_logTitle, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
public async Task<bool> CheckConnection()
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
public string? destinationPort { get; set; }
|
||||
public string? host { get; set; }
|
||||
public string? nsMode { get; set; }
|
||||
public object uid { get; set; }
|
||||
public object? uid { get; set; }
|
||||
public string? process { get; set; }
|
||||
public string? processPath { get; set; }
|
||||
public string? remoteDestination { get; set; }
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
public SystemProxyItem SystemProxyItem { get; set; }
|
||||
public WebDavItem WebDavItem { get; set; }
|
||||
public CheckUpdateItem CheckUpdateItem { get; set; }
|
||||
public Fragment4RayItem? Fragment4RayItem { get; set; }
|
||||
public List<InItem> Inbound { get; set; }
|
||||
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
||||
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
||||
|
||||
@@ -67,21 +67,13 @@
|
||||
public class GUIItem
|
||||
{
|
||||
public bool AutoRun { get; set; }
|
||||
|
||||
public bool EnableStatistics { get; set; }
|
||||
|
||||
public bool DisplayRealTimeSpeed { get; set; }
|
||||
public bool KeepOlderDedupl { get; set; }
|
||||
|
||||
public bool IgnoreGeoUpdateCore { get; set; } = true;
|
||||
|
||||
public int AutoUpdateInterval { get; set; }
|
||||
|
||||
public bool EnableSecurityProtocolTls13 { get; set; }
|
||||
|
||||
public int TrayMenuServersLimit { get; set; } = 20;
|
||||
|
||||
public bool EnableHWA { get; set; } = false;
|
||||
|
||||
public bool EnableLog { get; set; } = true;
|
||||
}
|
||||
|
||||
@@ -102,9 +94,8 @@
|
||||
public double MainGirdHeight1 { get; set; }
|
||||
public double MainGirdHeight2 { get; set; }
|
||||
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
||||
public bool ColorModeDark { get; set; }
|
||||
public bool FollowSystemTheme { get; set; }
|
||||
public string? ColorPrimaryName { get; set; }
|
||||
public string? CurrentTheme { get; set; }
|
||||
public string CurrentLanguage { get; set; }
|
||||
public string CurrentFontFamily { get; set; }
|
||||
public int CurrentFontSize { get; set; }
|
||||
@@ -119,8 +110,7 @@
|
||||
[Serializable]
|
||||
public class ConstItem
|
||||
{
|
||||
public string DefIEProxyExceptions { get; set; }
|
||||
public string SubConvertUrl { get; set; } = string.Empty;
|
||||
public string? SubConvertUrl { get; set; }
|
||||
public string? GeoSourceUrl { get; set; }
|
||||
public string? SrsSourceUrl { get; set; }
|
||||
public string? RouteRulesTemplateSourceUrl { get; set; }
|
||||
@@ -246,4 +236,12 @@
|
||||
public bool CheckPreReleaseUpdate { get; set; }
|
||||
public List<string>? SelectedCoreTypes { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Fragment4RayItem
|
||||
{
|
||||
public string? Packets { get; set; }
|
||||
public string? Length { get; set; }
|
||||
public string? Interval { get; set; }
|
||||
}
|
||||
}
|
||||
94
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
94
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -843,6 +843,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Copy proxy command to clipboard 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuCopyProxyCmdToClipboard {
|
||||
get {
|
||||
return ResourceManager.GetString("menuCopyProxyCmdToClipboard", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Clone selected server 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -942,15 +951,6 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Import old config (guiNConfig) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuImportOldGuiConfig {
|
||||
get {
|
||||
return ResourceManager.GetString("menuImportOldGuiConfig", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Import Rules From Clipboard 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -1248,6 +1248,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Iran 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuRegionalPresetsIran {
|
||||
get {
|
||||
return ResourceManager.GetString("menuRegionalPresetsIran", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Russia 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -1339,7 +1348,7 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Import Advanced Rules 的本地化字符串。
|
||||
/// 查找类似 Import Rules 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuRoutingAdvancedImportRules {
|
||||
get {
|
||||
@@ -1527,15 +1536,6 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Save Interface Layout 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuStorageUI {
|
||||
get {
|
||||
return ResourceManager.GetString("menuStorageUI", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2347,15 +2347,6 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable advanced function 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbenableRoutingAdvanced {
|
||||
get {
|
||||
return ResourceManager.GetString("TbenableRoutingAdvanced", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable Tun 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2806,15 +2797,6 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Dark Mode 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsColorMode {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsColorMode", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Core: basic settings 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2932,6 +2914,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Display real-time speed 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsDisplayRealTimeSpeed {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsDisplayRealTimeSpeed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Outbound DNS address 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -3085,15 +3076,6 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Follow System Theme 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsFollowSystemTheme {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsFollowSystemTheme", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Font Size 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -3139,15 +3121,6 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Ignore Geo files when updating core 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsIgnoreGeoUpdateCore {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsIgnoreGeoUpdateCore", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Keep older when deduplication 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -3428,7 +3401,7 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable Statistics (Require restart) 的本地化字符串。
|
||||
/// 查找类似 Enable traffic statistics (Require restart) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsStatistics {
|
||||
get {
|
||||
@@ -3454,6 +3427,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Theme 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTheme {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsTheme", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable Security Protocol TLS v1.3 (subscription/update) 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -481,9 +481,6 @@
|
||||
<data name="TbSettingsColor" xml:space="preserve">
|
||||
<value>رنگ</value>
|
||||
</data>
|
||||
<data name="TbSettingsColorMode" xml:space="preserve">
|
||||
<value>حالت تاریک</value>
|
||||
</data>
|
||||
<data name="TbSettingsLanguage" xml:space="preserve">
|
||||
<value>زبان</value>
|
||||
</data>
|
||||
@@ -721,8 +718,8 @@
|
||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
||||
<value>پورت Http</value>
|
||||
</data>
|
||||
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
|
||||
<value>هنگام بهروزرسانی هسته، فایلهای Geo را نادیده بگیرید</value>
|
||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||
<value>نمایش سرعت در زمان واقعی</value>
|
||||
</data>
|
||||
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
||||
<value>هنگام کپی برداری، نگه داری قدیمی تر ها</value>
|
||||
@@ -839,7 +836,7 @@
|
||||
<value>اضافه کردن</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedImportRules" xml:space="preserve">
|
||||
<value>وارد کردن قوانین پیشرفته</value>
|
||||
<value>وارد کردن مجموعه قوانین</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedRemove" xml:space="preserve">
|
||||
<value>حذف انتخاب شده</value>
|
||||
@@ -853,9 +850,6 @@
|
||||
<data name="TbdomainStrategy" xml:space="preserve">
|
||||
<value>استراتژی دامنه</value>
|
||||
</data>
|
||||
<data name="TbenableRoutingAdvanced" xml:space="preserve">
|
||||
<value>فعال کردن عملکرد پیشرفته</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
||||
<value>3. مسدود کردن دامنه یا آیپی</value>
|
||||
</data>
|
||||
@@ -940,9 +934,6 @@
|
||||
<data name="TbDisplayLog" xml:space="preserve">
|
||||
<value>نمایش گزارش</value>
|
||||
</data>
|
||||
<data name="menuImportOldGuiConfig" xml:space="preserve">
|
||||
<value>پیکربندی قدیمی guiNConfig را وارد شود</value>
|
||||
</data>
|
||||
<data name="TbEnableTunAs" xml:space="preserve">
|
||||
<value>فعال سازی Tun</value>
|
||||
</data>
|
||||
@@ -1105,9 +1096,6 @@
|
||||
<data name="TipActiveServer" xml:space="preserve">
|
||||
<value>فعال سازی</value>
|
||||
</data>
|
||||
<data name="menuStorageUI" xml:space="preserve">
|
||||
<value>ذخیره طرح رابط</value>
|
||||
</data>
|
||||
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
|
||||
<value>منبع فایل های جغرافیایی (اختیاری)</value>
|
||||
</data>
|
||||
@@ -1129,6 +1117,9 @@
|
||||
<data name="menuRegionalPresetsRussia" xml:space="preserve">
|
||||
<value>روسیه</value>
|
||||
</data>
|
||||
<data name="menuRegionalPresetsIran" xml:space="preserve">
|
||||
<value>ایران</value>
|
||||
</data>
|
||||
<data name="TbSettingsChinaUserTip" xml:space="preserve">
|
||||
<value>کاربران در منطقه چین می توانند این مورد را نادیده بگیرند</value>
|
||||
</data>
|
||||
@@ -1270,9 +1261,6 @@
|
||||
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
||||
<value>حداکتر پهنای باند هیستریا (آپلود/دانلود)</value>
|
||||
</data>
|
||||
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
|
||||
<value>دنبال کردن تم سیستم</value>
|
||||
</data>
|
||||
<data name="menuAddTuicServer" xml:space="preserve">
|
||||
<value>افزودن سرور [TUIC]</value>
|
||||
</data>
|
||||
@@ -1399,4 +1387,10 @@
|
||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||
<value>socks:پورت محلی، socks2: پورت دوم محلی، socks3: پورت LAN</value>
|
||||
</data>
|
||||
<data name="TbSettingsTheme" xml:space="preserve">
|
||||
<value>تم</value>
|
||||
</data>
|
||||
<data name="menuCopyProxyCmdToClipboard" xml:space="preserve">
|
||||
<value>کپی کردن دستور پروکسی در کلیپ بورد</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -481,12 +481,6 @@
|
||||
<data name="TbSettingsColor" xml:space="preserve">
|
||||
<value>Szín</value>
|
||||
</data>
|
||||
<data name="TbSettingsColorMode" xml:space="preserve">
|
||||
<value>Sötét mód</value>
|
||||
</data>
|
||||
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
|
||||
<value>Kövesse a rendszer témáját</value>
|
||||
</data>
|
||||
<data name="TbSettingsLanguage" xml:space="preserve">
|
||||
<value>Nyelv (Újraindítás)</value>
|
||||
</data>
|
||||
@@ -724,8 +718,8 @@
|
||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
||||
<value>HTTP Port</value>
|
||||
</data>
|
||||
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
|
||||
<value>Geo fájlok figyelmen kívül hagyása a yalap frissítésekor</value>
|
||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||
<value>Display real-time speed</value>
|
||||
</data>
|
||||
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
||||
<value>Régi megőrzése a deduplikáció során</value>
|
||||
@@ -856,9 +850,6 @@
|
||||
<data name="TbdomainStrategy" xml:space="preserve">
|
||||
<value>Domain stratégia</value>
|
||||
</data>
|
||||
<data name="TbenableRoutingAdvanced" xml:space="preserve">
|
||||
<value>Fejlett funkció engedélyezése</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
||||
<value>3. Domain vagy IP blokkolása</value>
|
||||
</data>
|
||||
@@ -943,9 +934,6 @@
|
||||
<data name="TbDisplayLog" xml:space="preserve">
|
||||
<value>Napló megjelenítése</value>
|
||||
</data>
|
||||
<data name="menuImportOldGuiConfig" xml:space="preserve">
|
||||
<value>Régi konfiguráció importálása (guiNConfig)</value>
|
||||
</data>
|
||||
<data name="TbEnableTunAs" xml:space="preserve">
|
||||
<value>Tun engedélyezése</value>
|
||||
</data>
|
||||
@@ -1318,9 +1306,6 @@
|
||||
<data name="TipActiveServer" xml:space="preserve">
|
||||
<value>Aktív</value>
|
||||
</data>
|
||||
<data name="menuStorageUI" xml:space="preserve">
|
||||
<value>Szoftverfelület elmentése</value>
|
||||
</data>
|
||||
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
|
||||
<value>Geo fájlok forrása (opcionális)</value>
|
||||
</data>
|
||||
@@ -1342,6 +1327,9 @@
|
||||
<data name="menuRegionalPresetsRussia" xml:space="preserve">
|
||||
<value>Oroszország</value>
|
||||
</data>
|
||||
<data name="menuRegionalPresetsIran" xml:space="preserve">
|
||||
<value>Irán</value>
|
||||
</data>
|
||||
<data name="TbSettingsChinaUserTip" xml:space="preserve">
|
||||
<value>A Kínában élő felhasználók figyelmen kívül hagyhatják ezt a tételt</value>
|
||||
</data>
|
||||
@@ -1399,4 +1387,10 @@
|
||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||
<value>socks: local port, socks2: second local port, socks3: LAN port</value>
|
||||
</data>
|
||||
<data name="TbSettingsTheme" xml:space="preserve">
|
||||
<value>Theme</value>
|
||||
</data>
|
||||
<data name="menuCopyProxyCmdToClipboard" xml:space="preserve">
|
||||
<value>Copy proxy command to clipboard</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -481,12 +481,6 @@
|
||||
<data name="TbSettingsColor" xml:space="preserve">
|
||||
<value>Color</value>
|
||||
</data>
|
||||
<data name="TbSettingsColorMode" xml:space="preserve">
|
||||
<value>Dark Mode</value>
|
||||
</data>
|
||||
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
|
||||
<value>Follow System Theme</value>
|
||||
</data>
|
||||
<data name="TbSettingsLanguage" xml:space="preserve">
|
||||
<value>Language (Restart)</value>
|
||||
</data>
|
||||
@@ -724,8 +718,8 @@
|
||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
||||
<value>HTTP Port</value>
|
||||
</data>
|
||||
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
|
||||
<value>Ignore Geo files when updating core</value>
|
||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||
<value>Display real-time speed (Require restart)</value>
|
||||
</data>
|
||||
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
||||
<value>Keep older when deduplication</value>
|
||||
@@ -761,7 +755,7 @@
|
||||
<value>Start on boot</value>
|
||||
</data>
|
||||
<data name="TbSettingsStatistics" xml:space="preserve">
|
||||
<value>Enable Statistics (Require restart)</value>
|
||||
<value>Enable traffic statistics (Require restart)</value>
|
||||
</data>
|
||||
<data name="TbSettingsSubConvert" xml:space="preserve">
|
||||
<value>Subscription conversion URL</value>
|
||||
@@ -842,7 +836,7 @@
|
||||
<value>Add</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedImportRules" xml:space="preserve">
|
||||
<value>Import Advanced Rules</value>
|
||||
<value>Import Rules</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedRemove" xml:space="preserve">
|
||||
<value>Remove selected (Delete)</value>
|
||||
@@ -856,9 +850,6 @@
|
||||
<data name="TbdomainStrategy" xml:space="preserve">
|
||||
<value>Domain strategy</value>
|
||||
</data>
|
||||
<data name="TbenableRoutingAdvanced" xml:space="preserve">
|
||||
<value>Enable advanced function</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
||||
<value>3.Block Domain or IP</value>
|
||||
</data>
|
||||
@@ -943,9 +934,6 @@
|
||||
<data name="TbDisplayLog" xml:space="preserve">
|
||||
<value>Display Log</value>
|
||||
</data>
|
||||
<data name="menuImportOldGuiConfig" xml:space="preserve">
|
||||
<value>Import old config (guiNConfig)</value>
|
||||
</data>
|
||||
<data name="TbEnableTunAs" xml:space="preserve">
|
||||
<value>Enable Tun</value>
|
||||
</data>
|
||||
@@ -1318,9 +1306,6 @@
|
||||
<data name="TipActiveServer" xml:space="preserve">
|
||||
<value>Active</value>
|
||||
</data>
|
||||
<data name="menuStorageUI" xml:space="preserve">
|
||||
<value>Save Interface Layout</value>
|
||||
</data>
|
||||
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
|
||||
<value>Geo files source (optional)</value>
|
||||
</data>
|
||||
@@ -1342,6 +1327,9 @@
|
||||
<data name="menuRegionalPresetsRussia" xml:space="preserve">
|
||||
<value>Russia</value>
|
||||
</data>
|
||||
<data name="menuRegionalPresetsIran" xml:space="preserve">
|
||||
<value>Iran</value>
|
||||
</data>
|
||||
<data name="TbSettingsChinaUserTip" xml:space="preserve">
|
||||
<value>Users in China region can ignore this item</value>
|
||||
</data>
|
||||
@@ -1399,4 +1387,10 @@
|
||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||
<value>socks: local port, socks2: second local port, socks3: LAN port</value>
|
||||
</data>
|
||||
<data name="TbSettingsTheme" xml:space="preserve">
|
||||
<value>Theme</value>
|
||||
</data>
|
||||
<data name="menuCopyProxyCmdToClipboard" xml:space="preserve">
|
||||
<value>Copy proxy command to clipboard</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -481,12 +481,6 @@
|
||||
<data name="TbSettingsColor" xml:space="preserve">
|
||||
<value>Цвет</value>
|
||||
</data>
|
||||
<data name="TbSettingsColorMode" xml:space="preserve">
|
||||
<value>Тёмный режим</value>
|
||||
</data>
|
||||
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
|
||||
<value>Следить за системной темой</value>
|
||||
</data>
|
||||
<data name="TbSettingsLanguage" xml:space="preserve">
|
||||
<value>Язык (требуется перезапуск)</value>
|
||||
</data>
|
||||
@@ -730,8 +724,8 @@
|
||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
||||
<value>HTTP порт</value>
|
||||
</data>
|
||||
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
|
||||
<value>Игнорировать файлы Geo при обновлении ядра</value>
|
||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||
<value>Display real-time speed</value>
|
||||
</data>
|
||||
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
||||
<value>Сохранить старые при удалении дублей</value>
|
||||
@@ -862,9 +856,6 @@
|
||||
<data name="TbdomainStrategy" xml:space="preserve">
|
||||
<value>Доменная стратегия</value>
|
||||
</data>
|
||||
<data name="TbenableRoutingAdvanced" xml:space="preserve">
|
||||
<value>Включить расширенные функции</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
||||
<value>3.Заблокировать домен или IP</value>
|
||||
</data>
|
||||
@@ -949,9 +940,6 @@
|
||||
<data name="TbDisplayLog" xml:space="preserve">
|
||||
<value>Показать логи</value>
|
||||
</data>
|
||||
<data name="menuImportOldGuiConfig" xml:space="preserve">
|
||||
<value>Импортировать старый конфиг guiNConfig</value>
|
||||
</data>
|
||||
<data name="TbEnableTunAs" xml:space="preserve">
|
||||
<value>Режим VPN</value>
|
||||
</data>
|
||||
@@ -1039,6 +1027,9 @@
|
||||
<data name="menuRegionalPresetsRussia" xml:space="preserve">
|
||||
<value>Россия</value>
|
||||
</data>
|
||||
<data name="menuRegionalPresetsIran" xml:space="preserve">
|
||||
<value>Иран</value>
|
||||
</data>
|
||||
<data name="TbSettingsChinaUserTip" xml:space="preserve">
|
||||
<value>Используйте Настройки -> Региональные пресеты вместо изменения этого поля</value>
|
||||
</data>
|
||||
@@ -1267,9 +1258,6 @@
|
||||
<data name="LvConvertTarget" xml:space="preserve">
|
||||
<value>Convert target type</value>
|
||||
</data>
|
||||
<data name="menuStorageUI" xml:space="preserve">
|
||||
<value>Save Interface Layout</value>
|
||||
</data>
|
||||
<data name="SpeedDisplayText" xml:space="preserve">
|
||||
<value>{0} : {1}/s↑ | {2}/s↓</value>
|
||||
</data>
|
||||
@@ -1399,4 +1387,10 @@
|
||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||
<value>socks: local port, socks2: second local port, socks3: LAN port</value>
|
||||
</data>
|
||||
<data name="TbSettingsTheme" xml:space="preserve">
|
||||
<value>Theme</value>
|
||||
</data>
|
||||
<data name="menuCopyProxyCmdToClipboard" xml:space="preserve">
|
||||
<value>Copy proxy command to clipboard</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -127,7 +127,7 @@
|
||||
<value>配置格式不正确</value>
|
||||
</data>
|
||||
<data name="CustomServerTips" xml:space="preserve">
|
||||
<value>注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手动修改监听端口。</value>
|
||||
<value>注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手动修改监听端口。</value>
|
||||
</data>
|
||||
<data name="Downloading" xml:space="preserve">
|
||||
<value>下载开始...</value>
|
||||
@@ -136,7 +136,7 @@
|
||||
<value>下载</value>
|
||||
</data>
|
||||
<data name="DownloadYesNo" xml:space="preserve">
|
||||
<value>是否下载? {0}</value>
|
||||
<value>是否下载?{0}</value>
|
||||
</data>
|
||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||
<value>转换配置文件失败</value>
|
||||
@@ -154,7 +154,7 @@
|
||||
<value>读取配置文件失败</value>
|
||||
</data>
|
||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||
<value>请填写正确格式服务器端口</value>
|
||||
<value>请填写正确格式的服务器端口</value>
|
||||
</data>
|
||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||
<value>请填写本地监听端口</value>
|
||||
@@ -169,16 +169,16 @@
|
||||
<value>请填写用户ID</value>
|
||||
</data>
|
||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||
<value>不是正确的配置,请检查</value>
|
||||
<value>配置不正确,请检查</value>
|
||||
</data>
|
||||
<data name="InitialConfiguration" xml:space="preserve">
|
||||
<value>初始化配置</value>
|
||||
</data>
|
||||
<data name="IsLatestCore" xml:space="preserve">
|
||||
<value>{0} {1} 已是最新版本。</value>
|
||||
<value>{0} {1} 已是最新版本</value>
|
||||
</data>
|
||||
<data name="IsLatestN" xml:space="preserve">
|
||||
<value>{0} {1} 已是最新版本。</value>
|
||||
<value>{0} {1} 已是最新版本</value>
|
||||
</data>
|
||||
<data name="LvAddress" xml:space="preserve">
|
||||
<value>地址</value>
|
||||
@@ -226,7 +226,7 @@
|
||||
<value>未设置有效的订阅</value>
|
||||
</data>
|
||||
<data name="MsgParsingSuccessfully" xml:space="preserve">
|
||||
<value>解析{0}成功</value>
|
||||
<value>解析 {0} 成功</value>
|
||||
</data>
|
||||
<data name="MsgStartGettingSubscriptions" xml:space="preserve">
|
||||
<value>开始获取订阅内容</value>
|
||||
@@ -259,10 +259,10 @@
|
||||
<value>在文件夹 ({0}) 下未找到Core文件 (文件名:{1}),请下载后放入文件夹,下载地址: {2}</value>
|
||||
</data>
|
||||
<data name="NoValidQRcodeFound" xml:space="preserve">
|
||||
<value>扫描完成,未发现有效二维码</value>
|
||||
<value>扫描完成,未发现有效二维码</value>
|
||||
</data>
|
||||
<data name="OperationFailed" xml:space="preserve">
|
||||
<value>操作失败,请检查重试</value>
|
||||
<value>操作失败,请检查并重试</value>
|
||||
</data>
|
||||
<data name="PleaseFillRemarks" xml:space="preserve">
|
||||
<value>请填写别名</value>
|
||||
@@ -280,10 +280,10 @@
|
||||
<value>服务器去重完成。原数量: {0},现数量: {1}</value>
|
||||
</data>
|
||||
<data name="RemoveServer" xml:space="preserve">
|
||||
<value>是否确定移除服务器?</value>
|
||||
<value>是否确定移除服务器?</value>
|
||||
</data>
|
||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||
<value>客户端配置文件保存在:{0}</value>
|
||||
<value>客户端配置文件保存在:{0}</value>
|
||||
</data>
|
||||
<data name="StartService" xml:space="preserve">
|
||||
<value>启动服务({0})...</value>
|
||||
@@ -311,10 +311,10 @@
|
||||
<value>请先选择规则</value>
|
||||
</data>
|
||||
<data name="RemoveRules" xml:space="preserve">
|
||||
<value>是否确定移除规则?</value>
|
||||
<value>是否确定移除规则?</value>
|
||||
</data>
|
||||
<data name="RoutingRuleDetailRequiredTips" xml:space="preserve">
|
||||
<value>{0},必填其中一项.</value>
|
||||
<value>{0},必填其中一项.</value>
|
||||
</data>
|
||||
<data name="LvRemarks" xml:space="preserve">
|
||||
<value>别名</value>
|
||||
@@ -329,10 +329,10 @@
|
||||
<value>请填写Url</value>
|
||||
</data>
|
||||
<data name="AddBatchRoutingRulesYesNo" xml:space="preserve">
|
||||
<value>是否追加规则?选择是则追加,选择否则替换</value>
|
||||
<value>是否追加规则?选择“是”则追加,选择“否”则全部替换。</value>
|
||||
</data>
|
||||
<data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve">
|
||||
<value>下载 GeoFile: {0} 成功</value>
|
||||
<value>下载 GeoFile:{0} 成功</value>
|
||||
</data>
|
||||
<data name="MsgInformationTitle" xml:space="preserve">
|
||||
<value>信息</value>
|
||||
@@ -386,7 +386,7 @@
|
||||
<value>*Kcp seed</value>
|
||||
</data>
|
||||
<data name="RegisterGlobalHotkeyFailed" xml:space="preserve">
|
||||
<value>注册全局热键 {0} 失败,原因 {1}</value>
|
||||
<value>注册全局热键 {0} 失败,原因:{1}</value>
|
||||
</data>
|
||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||
<value>注册全局热键 {0} 成功</value>
|
||||
@@ -481,14 +481,8 @@
|
||||
<data name="TbSettingsColor" xml:space="preserve">
|
||||
<value>颜色</value>
|
||||
</data>
|
||||
<data name="TbSettingsColorMode" xml:space="preserve">
|
||||
<value>暗黑模式</value>
|
||||
</data>
|
||||
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
|
||||
<value>是否跟随系统主题</value>
|
||||
</data>
|
||||
<data name="TbSettingsLanguage" xml:space="preserve">
|
||||
<value>语言(重启)</value>
|
||||
<value>语言(需重启)</value>
|
||||
</data>
|
||||
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
||||
<value>从剪贴板导入分享链接 (Ctrl+V)</value>
|
||||
@@ -638,7 +632,7 @@
|
||||
<value>传输层安全(TLS)</value>
|
||||
</data>
|
||||
<data name="TipNetwork" xml:space="preserve">
|
||||
<value>*默认tcp,选错会无法连接</value>
|
||||
<value>*默认tcp,选错会无法连接</value>
|
||||
</data>
|
||||
<data name="TbCoreType" xml:space="preserve">
|
||||
<value>Core类型</value>
|
||||
@@ -671,7 +665,7 @@
|
||||
<value>Socks端口</value>
|
||||
</data>
|
||||
<data name="TipPreSocksPort" xml:space="preserve">
|
||||
<value>* 自定义配置的Socks端口值,可不设置;当设置此值后,将使用Xray/sing-box(Tun)额外启动一个前置Socks服务,提供分流和速度显示等功能</value>
|
||||
<value>*自定义配置的Socks端口值,可不设置;当设置此值后,将使用Xray/sing-box(Tun)额外启动一个前置Socks服务,提供分流和速度显示等功能</value>
|
||||
</data>
|
||||
<data name="TbBrowse" xml:space="preserve">
|
||||
<value>浏览</value>
|
||||
@@ -680,7 +674,7 @@
|
||||
<value>编辑</value>
|
||||
</data>
|
||||
<data name="TbSettingsAdvancedProtocol" xml:space="preserve">
|
||||
<value>高级代理设置, 协议选择(可选)</value>
|
||||
<value>高级代理设置,协议选择(可选)</value>
|
||||
</data>
|
||||
<data name="TbSettingsAllowLAN" xml:space="preserve">
|
||||
<value>允许来自局域网的连接</value>
|
||||
@@ -689,19 +683,19 @@
|
||||
<value>启动后隐藏窗口</value>
|
||||
</data>
|
||||
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
|
||||
<value>自动更新Geo文件的间隔(单位小时)</value>
|
||||
<value>自动更新Geo文件的间隔(小时)</value>
|
||||
</data>
|
||||
<data name="TbSettingsCore" xml:space="preserve">
|
||||
<value>Core: 基础设置</value>
|
||||
</data>
|
||||
<data name="TbSettingsCoreDns" xml:space="preserve">
|
||||
<value>V2ray DNS设置</value>
|
||||
<value>v2ray DNS设置</value>
|
||||
</data>
|
||||
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
||||
<value>Core: KCP设置</value>
|
||||
</data>
|
||||
<data name="TbSettingsCoreType" xml:space="preserve">
|
||||
<value>Core类型设置</value>
|
||||
<value>Core 类型设置</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefAllowInsecure" xml:space="preserve">
|
||||
<value>默认跳过证书验证(allowInsecure)</value>
|
||||
@@ -719,13 +713,13 @@
|
||||
<value>例外</value>
|
||||
</data>
|
||||
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
||||
<value>例外. 对于下列字符开头的地址不使用代理配置文件:使用分号(;)分隔</value>
|
||||
<value>例外:对于下列字符开头的地址,不使用代理配置文件。使用分号(;)分隔。</value>
|
||||
</data>
|
||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
||||
<value>本地http监听端口</value>
|
||||
</data>
|
||||
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
|
||||
<value>更新Core时忽略Geo文件</value>
|
||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||
<value>显示实时速度(需重启)</value>
|
||||
</data>
|
||||
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
||||
<value>去重时保留序号较小的项</value>
|
||||
@@ -746,7 +740,7 @@
|
||||
<value>认证密码</value>
|
||||
</data>
|
||||
<data name="TbSettingsRemoteDNS" xml:space="preserve">
|
||||
<value>自定义DNS(可多个,用逗号(,)分隔)</value>
|
||||
<value>自定义DNS(可多个,用逗号(,)分隔)</value>
|
||||
</data>
|
||||
<data name="TbSettingsSetUWP" xml:space="preserve">
|
||||
<value>解除Win10 UWP应用回环代理限制</value>
|
||||
@@ -761,7 +755,7 @@
|
||||
<value>开机启动(可能会不成功)</value>
|
||||
</data>
|
||||
<data name="TbSettingsStatistics" xml:space="preserve">
|
||||
<value>启用统计(实时网速显示,需重启)</value>
|
||||
<value>启用流量统计(需重启)</value>
|
||||
</data>
|
||||
<data name="TbSettingsSubConvert" xml:space="preserve">
|
||||
<value>订阅转换网址(可选)</value>
|
||||
@@ -791,7 +785,7 @@
|
||||
<value>全局热键设置</value>
|
||||
</data>
|
||||
<data name="TbGlobalHotkeySettingTip" xml:space="preserve">
|
||||
<value>直接按键盘进行设置, 重启后生效</value>
|
||||
<value>直接按键盘进行设置,重启后生效</value>
|
||||
</data>
|
||||
<data name="TbNotChangeSystemProxy" xml:space="preserve">
|
||||
<value>不改变系统代理</value>
|
||||
@@ -830,7 +824,7 @@
|
||||
<value>上移 (U)</value>
|
||||
</data>
|
||||
<data name="MsgFilterTitle" xml:space="preserve">
|
||||
<value>过滤器, 支持正则</value>
|
||||
<value>过滤器(支持正则)</value>
|
||||
</data>
|
||||
<data name="menuWebsiteItem" xml:space="preserve">
|
||||
<value>{0} 官网</value>
|
||||
@@ -842,7 +836,7 @@
|
||||
<value>添加规则集</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedImportRules" xml:space="preserve">
|
||||
<value>一键导入高级规则</value>
|
||||
<value>一键导入规则集</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedRemove" xml:space="preserve">
|
||||
<value>移除所选规则 (Delete)</value>
|
||||
@@ -856,9 +850,6 @@
|
||||
<data name="TbdomainStrategy" xml:space="preserve">
|
||||
<value>域名解析策略</value>
|
||||
</data>
|
||||
<data name="TbenableRoutingAdvanced" xml:space="preserve">
|
||||
<value>启用高级功能</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
||||
<value>3.阻止的Domain或IP</value>
|
||||
</data>
|
||||
@@ -872,7 +863,7 @@
|
||||
<value>预定义规则集列表</value>
|
||||
</data>
|
||||
<data name="TbRoutingTips" xml:space="preserve">
|
||||
<value>*设置的路由规则,用逗号(,)分隔;正则中的逗号用<COMMA>替代</value>
|
||||
<value>*设置的路由规则,用逗号(,)分隔;正则中的逗号用<COMMA>替代</value>
|
||||
</data>
|
||||
<data name="menuImportRulesFromClipboard" xml:space="preserve">
|
||||
<value>从剪贴板中导入规则</value>
|
||||
@@ -902,13 +893,13 @@
|
||||
<value>路由规则详情设置</value>
|
||||
</data>
|
||||
<data name="TbAutoSort" xml:space="preserve">
|
||||
<value>保存时Domain, IP, 进程名 自动排序</value>
|
||||
<value>保存时 Domain, IP, 进程名 自动排序</value>
|
||||
</data>
|
||||
<data name="TbRuleobjectDoc" xml:space="preserve">
|
||||
<value>规则详细说明文档</value>
|
||||
</data>
|
||||
<data name="TbDnsObjectDoc" xml:space="preserve">
|
||||
<value>支持填写DnsObject,JSON格式,点击查看文档</value>
|
||||
<value>支持填写DnsObject,JSON格式,点击查看文档</value>
|
||||
</data>
|
||||
<data name="SubUrlTips" xml:space="preserve">
|
||||
<value>普通分组此处请留空</value>
|
||||
@@ -920,7 +911,7 @@
|
||||
<value>系统代理设置改变</value>
|
||||
</data>
|
||||
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
||||
<value>RouteOnly</value>
|
||||
<value>仅限路由(routeOnly)</value>
|
||||
</data>
|
||||
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||
<value>请勿将代理服务器用于本地(Intranet)地址</value>
|
||||
@@ -935,7 +926,7 @@
|
||||
<value>速度(M/s)</value>
|
||||
</data>
|
||||
<data name="FailedToRunCore" xml:space="preserve">
|
||||
<value>运行Core失败,请看日志</value>
|
||||
<value>运行Core失败,请查看日志</value>
|
||||
</data>
|
||||
<data name="LvFilter" xml:space="preserve">
|
||||
<value>别名正则过滤</value>
|
||||
@@ -943,9 +934,6 @@
|
||||
<data name="TbDisplayLog" xml:space="preserve">
|
||||
<value>显示日志</value>
|
||||
</data>
|
||||
<data name="menuImportOldGuiConfig" xml:space="preserve">
|
||||
<value>导入旧的配置文件guiNConfig</value>
|
||||
</data>
|
||||
<data name="TbEnableTunAs" xml:space="preserve">
|
||||
<value>启用Tun</value>
|
||||
</data>
|
||||
@@ -953,7 +941,7 @@
|
||||
<value>为局域网开启新的端口</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||
<value>Tun模式设置</value>
|
||||
<value>Tun 模式设置</value>
|
||||
</data>
|
||||
<data name="menuMoveToGroup" xml:space="preserve">
|
||||
<value>移至订阅分组</value>
|
||||
@@ -1315,9 +1303,6 @@
|
||||
<data name="TipActiveServer" xml:space="preserve">
|
||||
<value>活动</value>
|
||||
</data>
|
||||
<data name="menuStorageUI" xml:space="preserve">
|
||||
<value>保存界面布局</value>
|
||||
</data>
|
||||
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
|
||||
<value>Geo文件来源(可选)</value>
|
||||
</data>
|
||||
@@ -1342,6 +1327,9 @@
|
||||
<data name="menuRegionalPresetsRussia" xml:space="preserve">
|
||||
<value>俄罗斯</value>
|
||||
</data>
|
||||
<data name="menuRegionalPresetsIran" xml:space="preserve">
|
||||
<value>伊朗</value>
|
||||
</data>
|
||||
<data name="menuAddServerViaImage" xml:space="preserve">
|
||||
<value>扫描图片中的二维码</value>
|
||||
</data>
|
||||
@@ -1370,7 +1358,7 @@
|
||||
<value>请先在Tun模式设置中设置sudo密码</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
||||
<value>请不要用sudo运行本app</value>
|
||||
<value>请不要用sudo运行本程序</value>
|
||||
</data>
|
||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||
<value>*xhttp 模式</value>
|
||||
@@ -1385,7 +1373,7 @@
|
||||
<value>测试时自动分批的每批数量(最大1000)</value>
|
||||
</data>
|
||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||
<value>例外. 对于下列地址不使用代理配置文件:使用逗号(,)分隔</value>
|
||||
<value>例外:对于下列地址不使用代理配置文件。使用逗号(,)分隔。</value>
|
||||
</data>
|
||||
<data name="TbSettingsDestOverride" xml:space="preserve">
|
||||
<value>流量探测类型</value>
|
||||
@@ -1396,4 +1384,10 @@
|
||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||
<value>socks:本地端口,socks2:第二个本地端口,socks3:局域网端口</value>
|
||||
</data>
|
||||
<data name="TbSettingsTheme" xml:space="preserve">
|
||||
<value>主题</value>
|
||||
</data>
|
||||
<data name="menuCopyProxyCmdToClipboard" xml:space="preserve">
|
||||
<value>复制终端代理命令至剪贴板</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -136,7 +136,7 @@
|
||||
<value>下載</value>
|
||||
</data>
|
||||
<data name="DownloadYesNo" xml:space="preserve">
|
||||
<value>是否下載? {0}</value>
|
||||
<value>是否下載?{0}</value>
|
||||
</data>
|
||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||
<value>轉換設定檔失敗</value>
|
||||
@@ -154,7 +154,7 @@
|
||||
<value>讀取設定檔失敗</value>
|
||||
</data>
|
||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||
<value>請填寫正確格式伺服器埠</value>
|
||||
<value>請填寫正確格式的伺服器埠</value>
|
||||
</data>
|
||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||
<value>請填寫本機偵聽埠</value>
|
||||
@@ -169,16 +169,16 @@
|
||||
<value>請填寫使用者ID</value>
|
||||
</data>
|
||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||
<value>不是正確的設定,請檢查</value>
|
||||
<value>設定不正確,請檢查</value>
|
||||
</data>
|
||||
<data name="InitialConfiguration" xml:space="preserve">
|
||||
<value>初始化設定</value>
|
||||
</data>
|
||||
<data name="IsLatestCore" xml:space="preserve">
|
||||
<value>{0} {1} 已是最新版本。</value>
|
||||
<value>{0} {1} 已是最新版本</value>
|
||||
</data>
|
||||
<data name="IsLatestN" xml:space="preserve">
|
||||
<value>{0} {1} 已是最新版本。</value>
|
||||
<value>{0} {1} 已是最新版本</value>
|
||||
</data>
|
||||
<data name="LvAddress" xml:space="preserve">
|
||||
<value>位址</value>
|
||||
@@ -226,7 +226,7 @@
|
||||
<value>未設定有效的訂閱</value>
|
||||
</data>
|
||||
<data name="MsgParsingSuccessfully" xml:space="preserve">
|
||||
<value>解析{0}成功</value>
|
||||
<value>解析 {0} 成功</value>
|
||||
</data>
|
||||
<data name="MsgStartGettingSubscriptions" xml:space="preserve">
|
||||
<value>開始獲取訂閱內容</value>
|
||||
@@ -259,10 +259,10 @@
|
||||
<value>在資料夾 ({0}) 下未找到Core檔案 (檔案名:{1}),請下載後放入資料夾,下載網址: {2}</value>
|
||||
</data>
|
||||
<data name="NoValidQRcodeFound" xml:space="preserve">
|
||||
<value>掃描完成,未發現有效二維碼</value>
|
||||
<value>掃描完成,未發現有效二維碼</value>
|
||||
</data>
|
||||
<data name="OperationFailed" xml:space="preserve">
|
||||
<value>操作失敗,請檢查重試</value>
|
||||
<value>操作失敗,請檢查後重試</value>
|
||||
</data>
|
||||
<data name="PleaseFillRemarks" xml:space="preserve">
|
||||
<value>請填寫別名</value>
|
||||
@@ -280,16 +280,17 @@
|
||||
<value>伺服器去重完成。原數量: {0},現數量: {1}</value>
|
||||
</data>
|
||||
<data name="RemoveServer" xml:space="preserve">
|
||||
<value>是否確定移除伺服器?</value>
|
||||
<value>是否確定移除伺服器?</value>
|
||||
</data>
|
||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||
<value>用戶端設定檔儲存在:{0}</value>
|
||||
<value>用戶端設定檔儲存在:{0}</value>
|
||||
</data>
|
||||
<data name="StartService" xml:space="preserve">
|
||||
<value>啟動服務({0})...</value>
|
||||
</data>
|
||||
<data name="SuccessfulConfiguration" xml:space="preserve">
|
||||
<value>設定成功{0}</value>
|
||||
<value>設定成功
|
||||
{0}</value>
|
||||
</data>
|
||||
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
||||
<value>成功匯入自訂設定伺服器</value>
|
||||
@@ -310,10 +311,10 @@
|
||||
<value>請先選擇規則</value>
|
||||
</data>
|
||||
<data name="RemoveRules" xml:space="preserve">
|
||||
<value>是否確定移除規則?</value>
|
||||
<value>是否確定移除規則?</value>
|
||||
</data>
|
||||
<data name="RoutingRuleDetailRequiredTips" xml:space="preserve">
|
||||
<value>{0},必填其中一項.</value>
|
||||
<value>{0},必填其中一項.</value>
|
||||
</data>
|
||||
<data name="LvRemarks" xml:space="preserve">
|
||||
<value>別名</value>
|
||||
@@ -328,10 +329,10 @@
|
||||
<value>請填寫URL</value>
|
||||
</data>
|
||||
<data name="AddBatchRoutingRulesYesNo" xml:space="preserve">
|
||||
<value>是否追加規則?選擇是則追加,選擇否則取代</value>
|
||||
<value>是否追加規則?選擇“是”則追加,選擇“否”則完全取代。</value>
|
||||
</data>
|
||||
<data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve">
|
||||
<value>下載 GeoFile: {0} 成功</value>
|
||||
<value>下載 GeoFile:{0} 成功</value>
|
||||
</data>
|
||||
<data name="MsgInformationTitle" xml:space="preserve">
|
||||
<value>資訊</value>
|
||||
@@ -385,7 +386,7 @@
|
||||
<value>*KCP seed</value>
|
||||
</data>
|
||||
<data name="RegisterGlobalHotkeyFailed" xml:space="preserve">
|
||||
<value>註冊全域快速鍵 {0} 失敗,原因 {1}</value>
|
||||
<value>註冊全域快速鍵 {0} 失敗,原因:{1}</value>
|
||||
</data>
|
||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||
<value>註冊全域快速鍵 {0} 成功</value>
|
||||
@@ -480,14 +481,8 @@
|
||||
<data name="TbSettingsColor" xml:space="preserve">
|
||||
<value>顏色</value>
|
||||
</data>
|
||||
<data name="TbSettingsColorMode" xml:space="preserve">
|
||||
<value>暗黑模式</value>
|
||||
</data>
|
||||
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
|
||||
<value>是否跟隨系統主題</value>
|
||||
</data>
|
||||
<data name="TbSettingsLanguage" xml:space="preserve">
|
||||
<value>語言(重啟)</value>
|
||||
<value>語言(需重啟)</value>
|
||||
</data>
|
||||
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
||||
<value>從剪貼簿導入分享鏈接 (Ctrl+V)</value>
|
||||
@@ -637,7 +632,7 @@
|
||||
<value>傳輸層安全(TLS)</value>
|
||||
</data>
|
||||
<data name="TipNetwork" xml:space="preserve">
|
||||
<value>*預設TCP,選錯會無法連接</value>
|
||||
<value>*預設TCP,選錯會無法連接</value>
|
||||
</data>
|
||||
<data name="TbCoreType" xml:space="preserve">
|
||||
<value>Core類型</value>
|
||||
@@ -670,7 +665,7 @@
|
||||
<value>SOCKS埠</value>
|
||||
</data>
|
||||
<data name="TipPreSocksPort" xml:space="preserve">
|
||||
<value>* 自訂設定的Socks埠值,可不設定;當設定此值後,將使用Xray/sing-box(Tun)額外啟動一個前置Socks服務,提供分流和速度顯示等功能</value>
|
||||
<value>*自訂設定的Socks埠值,可不設定;當設定此值後,將使用Xray/sing-box(Tun)額外啟動一個前置Socks服務,提供分流和速度顯示等功能</value>
|
||||
</data>
|
||||
<!--********************************************-->
|
||||
<data name="TbBrowse" xml:space="preserve">
|
||||
@@ -680,7 +675,7 @@
|
||||
<value>編輯</value>
|
||||
</data>
|
||||
<data name="TbSettingsAdvancedProtocol" xml:space="preserve">
|
||||
<value>進階代理設定, 協定選擇(可選)</value>
|
||||
<value>進階代理設定,協定選擇(可選)</value>
|
||||
</data>
|
||||
<data name="TbSettingsAllowLAN" xml:space="preserve">
|
||||
<value>允許來自區域網路的連線</value>
|
||||
@@ -689,7 +684,7 @@
|
||||
<value>啟動後隱藏視窗</value>
|
||||
</data>
|
||||
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
|
||||
<value>自動更新Geo檔案的間隔(單位小時)</value>
|
||||
<value>自動更新Geo檔案的間隔(小時)</value>
|
||||
</data>
|
||||
<data name="TbSettingsCore" xml:space="preserve">
|
||||
<value>Core: 基礎設定</value>
|
||||
@@ -701,7 +696,7 @@
|
||||
<value>Core: KCP設定</value>
|
||||
</data>
|
||||
<data name="TbSettingsCoreType" xml:space="preserve">
|
||||
<value>Core類型設定</value>
|
||||
<value>Core 類型設定</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefAllowInsecure" xml:space="preserve">
|
||||
<value>預設跳過憑證驗證(allowinsecure)</value>
|
||||
@@ -719,13 +714,13 @@
|
||||
<value>例外</value>
|
||||
</data>
|
||||
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
||||
<value>例外. 對於下列字元開頭的位址不使用代理設定檔:使用分號(;)分隔</value>
|
||||
<value>例外:對於下列字元開頭的位址,不使用代理設定檔。使用分號(;)分隔。</value>
|
||||
</data>
|
||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
||||
<value>本機HTTP偵聽埠</value>
|
||||
</data>
|
||||
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
|
||||
<value>更新Core時忽略Geo檔案</value>
|
||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||
<value>顯示即時速度(需重啟)</value>
|
||||
</data>
|
||||
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
||||
<value>去重時保留序號較小的項</value>
|
||||
@@ -746,7 +741,7 @@
|
||||
<value>認證密碼</value>
|
||||
</data>
|
||||
<data name="TbSettingsRemoteDNS" xml:space="preserve">
|
||||
<value>自訂DNS(可多個,用逗號(,)分隔)</value>
|
||||
<value>自訂DNS(可多個,用逗號(,)分隔)</value>
|
||||
</data>
|
||||
<data name="TbSettingsSetUWP" xml:space="preserve">
|
||||
<value>解除Win10 UWP應用回環代理限制</value>
|
||||
@@ -761,7 +756,7 @@
|
||||
<value>開機啟動(可能會不成功)</value>
|
||||
</data>
|
||||
<data name="TbSettingsStatistics" xml:space="preserve">
|
||||
<value>啟用統計(即時網速顯示,需重啟)</value>
|
||||
<value>啟用流量統計(需重啟)</value>
|
||||
</data>
|
||||
<data name="TbSettingsSubConvert" xml:space="preserve">
|
||||
<value>訂閱轉換網址(可選)</value>
|
||||
@@ -791,7 +786,7 @@
|
||||
<value>全域快速鍵設定</value>
|
||||
</data>
|
||||
<data name="TbGlobalHotkeySettingTip" xml:space="preserve">
|
||||
<value>直接按鍵盤進行設定, 重啟後生效</value>
|
||||
<value>直接按鍵盤進行設定,重啟後生效</value>
|
||||
</data>
|
||||
<data name="TbNotChangeSystemProxy" xml:space="preserve">
|
||||
<value>不改變系統代理</value>
|
||||
@@ -830,7 +825,7 @@
|
||||
<value>上移 (U)</value>
|
||||
</data>
|
||||
<data name="MsgFilterTitle" xml:space="preserve">
|
||||
<value>過濾, 支援正則</value>
|
||||
<value>過濾(允許正則)</value>
|
||||
</data>
|
||||
<data name="menuWebsiteItem" xml:space="preserve">
|
||||
<value>{0} 官網</value>
|
||||
@@ -842,7 +837,7 @@
|
||||
<value>新增規則集</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedImportRules" xml:space="preserve">
|
||||
<value>一鍵匯入進階規則</value>
|
||||
<value>一鍵匯入規則集</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedRemove" xml:space="preserve">
|
||||
<value>移除所選規則 (Delete)</value>
|
||||
@@ -856,9 +851,6 @@
|
||||
<data name="TbdomainStrategy" xml:space="preserve">
|
||||
<value>域名解析策略</value>
|
||||
</data>
|
||||
<data name="TbenableRoutingAdvanced" xml:space="preserve">
|
||||
<value>啟動進階功能</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
||||
<value>3.阻止的Domain或IP</value>
|
||||
</data>
|
||||
@@ -872,7 +864,7 @@
|
||||
<value>預定義規則集列表</value>
|
||||
</data>
|
||||
<data name="TbRoutingTips" xml:space="preserve">
|
||||
<value>*設定的路由規則,用逗號(,)分隔;正則中的逗號用<COMMA>替代</value>
|
||||
<value>*設定的路由規則,用逗號(,)分隔;正則中的逗號用<COMMA>替代</value>
|
||||
</data>
|
||||
<data name="menuImportRulesFromClipboard" xml:space="preserve">
|
||||
<value>從剪貼簿中匯入規則</value>
|
||||
@@ -902,13 +894,13 @@
|
||||
<value>路由規則詳情設定</value>
|
||||
</data>
|
||||
<data name="TbAutoSort" xml:space="preserve">
|
||||
<value>儲存時Domain, IP, 行程名 自動排序</value>
|
||||
<value>儲存時 Domain, IP, 行程名 自動排序</value>
|
||||
</data>
|
||||
<data name="TbRuleobjectDoc" xml:space="preserve">
|
||||
<value>規則詳細說明檔案</value>
|
||||
</data>
|
||||
<data name="TbDnsObjectDoc" xml:space="preserve">
|
||||
<value>支援填寫DnsObject,JSON格式,點擊查看檔案</value>
|
||||
<value>支援填寫DnsObject,JSON格式,點擊查看説明</value>
|
||||
</data>
|
||||
<data name="SubUrlTips" xml:space="preserve">
|
||||
<value>普通分組此處請留空</value>
|
||||
@@ -920,7 +912,7 @@
|
||||
<value>系統代理設定已改變</value>
|
||||
</data>
|
||||
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
||||
<value>RouteOnly</value>
|
||||
<value>僅限路由(routeOnly)</value>
|
||||
</data>
|
||||
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||
<value>請勿將代理伺服器用於本機(Intranet)位址</value>
|
||||
@@ -935,7 +927,7 @@
|
||||
<value>速度(M/s)</value>
|
||||
</data>
|
||||
<data name="FailedToRunCore" xml:space="preserve">
|
||||
<value>執行Core失敗,請看日誌</value>
|
||||
<value>執行Core失敗,請查閲日誌</value>
|
||||
</data>
|
||||
<data name="LvFilter" xml:space="preserve">
|
||||
<value>別名正則過濾</value>
|
||||
@@ -943,17 +935,14 @@
|
||||
<data name="TbDisplayLog" xml:space="preserve">
|
||||
<value>顯示日誌</value>
|
||||
</data>
|
||||
<data name="menuImportOldGuiConfig" xml:space="preserve">
|
||||
<value>匯入舊的設定檔guiNConfig</value>
|
||||
</data>
|
||||
<data name="TbEnableTunAs" xml:space="preserve">
|
||||
<value>啟用TUN</value>
|
||||
<value>啟用Tun</value>
|
||||
</data>
|
||||
<data name="TbSettingsNewPort4LAN" xml:space="preserve">
|
||||
<value>為區域網路開啟新的埠</value>
|
||||
</data>
|
||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||
<value>TUN模式設定</value>
|
||||
<value>Tun 模式設定</value>
|
||||
</data>
|
||||
<data name="menuMoveToGroup" xml:space="preserve">
|
||||
<value>移至訂閱分組</value>
|
||||
@@ -1067,7 +1056,7 @@
|
||||
<value>sing-box Mux 多路復用協定</value>
|
||||
</data>
|
||||
<data name="TbRoutingRuleProcess" xml:space="preserve">
|
||||
<value>行程名全稱 (TUN模式)</value>
|
||||
<value>行程名全稱 (Tun模式)</value>
|
||||
</data>
|
||||
<data name="TbRoutingRuleDomain" xml:space="preserve">
|
||||
<value>Domain</value>
|
||||
@@ -1195,9 +1184,6 @@
|
||||
<data name="TipActiveServer" xml:space="preserve">
|
||||
<value>活動</value>
|
||||
</data>
|
||||
<data name="menuStorageUI" xml:space="preserve">
|
||||
<value>儲存介面佈局</value>
|
||||
</data>
|
||||
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
|
||||
<value>Geo檔案來源(可選)</value>
|
||||
</data>
|
||||
@@ -1222,6 +1208,9 @@
|
||||
<data name="menuRegionalPresetsRussia" xml:space="preserve">
|
||||
<value>俄羅斯</value>
|
||||
</data>
|
||||
<data name="menuRegionalPresetsIran" xml:space="preserve">
|
||||
<value>伊朗</value>
|
||||
</data>
|
||||
<data name="menuAddServerViaImage" xml:space="preserve">
|
||||
<value>掃描圖片中的二維碼</value>
|
||||
</data>
|
||||
@@ -1370,7 +1359,7 @@
|
||||
<value>請先在Tun模式設定中設定sudo密碼</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
||||
<value>請不要用sudo來運行本app</value>
|
||||
<value>請不要用sudo來運行此App</value>
|
||||
</data>
|
||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||
<value>*xhttp 模式</value>
|
||||
@@ -1385,7 +1374,7 @@
|
||||
<value>測試時自動分批的每批數量(最大1000)</value>
|
||||
</data>
|
||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||
<value>例外. 對於下列位址不使用代理設定檔:使用逗號(,)分隔</value>
|
||||
<value>例外:對於下列位址不使用代理設定檔,使用逗號(,)分隔。</value>
|
||||
</data>
|
||||
<data name="TbSettingsDestOverride" xml:space="preserve">
|
||||
<value>流量探測類型</value>
|
||||
@@ -1396,4 +1385,10 @@
|
||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||
<value>socks:本地端口,socks2:第二個本地端口,socks3:區域網路端口</value>
|
||||
</data>
|
||||
<data name="TbSettingsTheme" xml:space="preserve">
|
||||
<value>主題</value>
|
||||
</data>
|
||||
<data name="menuCopyProxyCmdToClipboard" xml:space="preserve">
|
||||
<value>複製終端代理指令至剪貼簿</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -5,24 +5,25 @@
|
||||
"loglevel": "warning"
|
||||
},
|
||||
"inbounds": [],
|
||||
"outbounds": [{
|
||||
"outbounds": [
|
||||
{
|
||||
"tag": "proxy",
|
||||
"protocol": "vmess",
|
||||
"settings": {
|
||||
"vnext": [{
|
||||
"address": "v2ray.cool",
|
||||
"port": 10086,
|
||||
"address": "",
|
||||
"port": 0,
|
||||
"users": [{
|
||||
"id": "a3482e88-686a-4a58-8126-99c9df64b7bf",
|
||||
"id": "",
|
||||
"security": "auto"
|
||||
}]
|
||||
}],
|
||||
"servers": [{
|
||||
"address": "v2ray.cool",
|
||||
"method": "chacha20",
|
||||
"address": "",
|
||||
"method": "",
|
||||
"ota": false,
|
||||
"password": "123456",
|
||||
"port": 10086,
|
||||
"password": "",
|
||||
"port": 0,
|
||||
"level": 1
|
||||
}]
|
||||
},
|
||||
@@ -35,27 +36,23 @@
|
||||
},
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"settings": {},
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"protocol": "blackhole",
|
||||
"tag": "block",
|
||||
"settings": {
|
||||
"response": {
|
||||
"type": "http"
|
||||
}
|
||||
}
|
||||
"tag": "block"
|
||||
}
|
||||
],
|
||||
"routing": {
|
||||
"domainStrategy": "IPIfNonMatch",
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": ["api"],
|
||||
"outboundTag": "api",
|
||||
"type": "field"
|
||||
}
|
||||
{
|
||||
"inboundTag": [
|
||||
"api"
|
||||
],
|
||||
"outboundTag": "api",
|
||||
"type": "field"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -99,10 +99,5 @@
|
||||
"domain": [
|
||||
"geosite:cn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "最终代理",
|
||||
"port": "0-65535",
|
||||
"outboundTag": "proxy"
|
||||
}
|
||||
]
|
||||
@@ -2,7 +2,7 @@
|
||||
"servers": [
|
||||
{
|
||||
"tag": "remote",
|
||||
"address": "8.8.8.8",
|
||||
"address": "tcp://8.8.8.8",
|
||||
"strategy": "prefer_ipv4",
|
||||
"detour": "proxy"
|
||||
},
|
||||
@@ -32,4 +32,4 @@
|
||||
}
|
||||
],
|
||||
"final": "remote"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,15 @@
|
||||
"proxy.example.com": "127.0.0.1"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"address": "1.1.1.1",
|
||||
"domains": [
|
||||
"geosite:geolocation-!cn"
|
||||
],
|
||||
"expectIPs": [
|
||||
"geoip:!cn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "223.5.5.5",
|
||||
"domains": [
|
||||
@@ -13,7 +22,6 @@
|
||||
"geoip:cn"
|
||||
]
|
||||
},
|
||||
"1.1.1.1",
|
||||
"8.8.8.8",
|
||||
"https://dns.google/dns-query"
|
||||
]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
"servers": [
|
||||
{
|
||||
"tag": "remote",
|
||||
"address": "8.8.8.8",
|
||||
"address": "tcp://8.8.8.8",
|
||||
"strategy": "prefer_ipv4",
|
||||
"detour": "proxy"
|
||||
},
|
||||
@@ -33,4 +33,4 @@
|
||||
}
|
||||
],
|
||||
"final": "remote"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>7.4.2</Version>
|
||||
<Version>7.7.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Downloader" Version="3.3.1" />
|
||||
<PackageReference Include="Downloader" Version="3.3.3" />
|
||||
<PackageReference Include="ReactiveUI" Version="20.1.63" />
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
|
||||
<PackageReference Include="Splat.NLog" Version="15.2.22" />
|
||||
<PackageReference Include="WebDav.Client" Version="2.8.0" />
|
||||
<PackageReference Include="YamlDotNet" Version="16.2.1" />
|
||||
<PackageReference Include="YamlDotNet" Version="16.3.0" />
|
||||
<PackageReference Include="QRCoder" Version="1.6.0" />
|
||||
<PackageReference Include="CliWrap" Version="3.7.0" />
|
||||
<PackageReference Include="CliWrap" Version="3.7.1" />
|
||||
<PackageReference Include="SkiaSharp.QrCode" Version="0.7.0" />
|
||||
<PackageReference Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
|
||||
<PackageReference Include="TaskScheduler" Version="2.11.0" />
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
public class CoreConfigClashService
|
||||
{
|
||||
private Config _config;
|
||||
private static readonly string _tag = "CoreConfigClashService";
|
||||
|
||||
public CoreConfigClashService(Config config)
|
||||
{
|
||||
@@ -131,7 +132,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("GenerateClientConfigClash-Mixin", ex);
|
||||
Logging.SaveLog($"{_tag}-Mixin", ex);
|
||||
}
|
||||
|
||||
var txtFileNew = YamlUtils.ToYaml(fileContent).Replace(tagYamlStr2, tagYamlStr3);
|
||||
@@ -151,7 +152,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("GenerateClientConfigClash", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
public class CoreConfigSingboxService
|
||||
{
|
||||
private Config _config;
|
||||
private static readonly string _tag = "CoreConfigSingboxService";
|
||||
|
||||
public CoreConfigSingboxService(Config config)
|
||||
{
|
||||
@@ -71,7 +72,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("GenerateClientConfig4Singbox", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
@@ -114,7 +115,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
await GenLog(singboxConfig);
|
||||
@@ -235,7 +236,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
@@ -312,7 +313,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||
await GenOutbound(item, outbound);
|
||||
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
|
||||
singboxConfig.outbounds.Add(outbound);
|
||||
singboxConfig.outbounds.Insert(0, outbound);
|
||||
tagProxy.Add(outbound.tag);
|
||||
}
|
||||
if (tagProxy.Count <= 0)
|
||||
@@ -332,7 +333,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
outbounds = tagProxy,
|
||||
interrupt_exist_connections = false,
|
||||
};
|
||||
singboxConfig.outbounds.Add(outUrltest);
|
||||
singboxConfig.outbounds.Insert(0, outUrltest);
|
||||
|
||||
//add selector outbound
|
||||
var outSelector = new Outbound4Sbox
|
||||
@@ -343,7 +344,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
interrupt_exist_connections = false,
|
||||
};
|
||||
outSelector.outbounds.Insert(0, outUrltest.tag);
|
||||
singboxConfig.outbounds.Add(outSelector);
|
||||
singboxConfig.outbounds.Insert(0, outSelector);
|
||||
|
||||
ret.Success = true;
|
||||
ret.Data = JsonUtils.Serialize(singboxConfig);
|
||||
@@ -351,7 +352,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
@@ -432,7 +433,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
@@ -473,9 +474,9 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<int> GenInbounds(SingboxConfig singboxConfig)
|
||||
@@ -562,7 +563,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -695,7 +696,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -718,9 +719,9 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<int> GenOutboundTls(ProfileItem node, Outbound4Sbox outbound)
|
||||
@@ -768,9 +769,9 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<int> GenOutboundTransport(ProfileItem node, Outbound4Sbox outbound)
|
||||
@@ -845,9 +846,9 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<int> GenMoreOutbounds(ProfileItem node, SingboxConfig singboxConfig)
|
||||
@@ -897,7 +898,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -969,7 +970,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1085,9 +1086,9 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private bool ParseV2Domain(string domain, Rule4Sbox rule)
|
||||
@@ -1184,7 +1185,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1239,7 +1240,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
|
||||
singboxConfig.dns = dns4Sbox;
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<int> GenExperimental(SingboxConfig singboxConfig)
|
||||
@@ -1258,11 +1259,12 @@ namespace ServiceLib.Services.CoreConfig
|
||||
singboxConfig.experimental ??= new Experimental4Sbox();
|
||||
singboxConfig.experimental.cache_file = new CacheFile4Sbox()
|
||||
{
|
||||
enabled = true
|
||||
enabled = true,
|
||||
path = Utils.GetConfigPath("cache.db")
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<int> ConvertGeo2Ruleset(SingboxConfig singboxConfig)
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
public class CoreConfigV2rayService
|
||||
{
|
||||
private Config _config;
|
||||
private static readonly string _tag = "CoreConfigV2rayService";
|
||||
|
||||
public CoreConfigV2rayService(Config config)
|
||||
{
|
||||
@@ -70,7 +71,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("GenerateClientConfig4V2ray", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
@@ -153,7 +154,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||
await GenOutbound(item, outbound);
|
||||
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
|
||||
v2rayConfig.outbounds.Add(outbound);
|
||||
v2rayConfig.outbounds.Insert(0, outbound);
|
||||
tagProxy.Add(outbound.tag);
|
||||
}
|
||||
if (tagProxy.Count <= 0)
|
||||
@@ -181,15 +182,12 @@ namespace ServiceLib.Services.CoreConfig
|
||||
rule.balancerTag = balancer.tag;
|
||||
}
|
||||
}
|
||||
else
|
||||
v2rayConfig.routing.rules.Add(new()
|
||||
{
|
||||
v2rayConfig.routing.rules.Add(new()
|
||||
{
|
||||
network = "tcp,udp",
|
||||
balancerTag = balancer.tag,
|
||||
type = "field"
|
||||
});
|
||||
}
|
||||
network = "tcp,udp",
|
||||
balancerTag = balancer.tag,
|
||||
type = "field"
|
||||
});
|
||||
|
||||
ret.Success = true;
|
||||
ret.Data = JsonUtils.Serialize(v2rayConfig);
|
||||
@@ -197,7 +195,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
@@ -240,7 +238,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
await GenLog(v2rayConfig);
|
||||
@@ -349,7 +347,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
@@ -379,9 +377,9 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<int> GenInbounds(V2rayConfig v2rayConfig)
|
||||
@@ -423,9 +421,9 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private Inbounds4Ray GetInbound(InItem inItem, EInboundProtocol protocol, bool bSocks)
|
||||
@@ -482,7 +480,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -560,15 +558,16 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound)
|
||||
{
|
||||
try
|
||||
{
|
||||
var muxEnabled = _config.CoreBasicItem.MuxEnabled;
|
||||
switch (node.ConfigType)
|
||||
{
|
||||
case EConfigType.VMess:
|
||||
@@ -609,7 +608,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
usersItem.security = Global.DefaultSecurity;
|
||||
}
|
||||
|
||||
await GenOutboundMux(node, outbound, _config.CoreBasicItem.MuxEnabled);
|
||||
await GenOutboundMux(node, outbound, muxEnabled, muxEnabled);
|
||||
|
||||
outbound.settings.servers = null;
|
||||
break;
|
||||
@@ -634,7 +633,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
serversItem.ota = false;
|
||||
serversItem.level = 1;
|
||||
|
||||
await GenOutboundMux(node, outbound, false);
|
||||
await GenOutboundMux(node, outbound);
|
||||
|
||||
outbound.settings.vnext = null;
|
||||
break;
|
||||
@@ -670,7 +669,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
serversItem.users = new List<SocksUsersItem4Ray>() { socksUsersItem };
|
||||
}
|
||||
|
||||
await GenOutboundMux(node, outbound, false);
|
||||
await GenOutboundMux(node, outbound);
|
||||
|
||||
outbound.settings.vnext = null;
|
||||
break;
|
||||
@@ -704,22 +703,15 @@ namespace ServiceLib.Services.CoreConfig
|
||||
usersItem.email = Global.UserEMail;
|
||||
usersItem.encryption = node.Security;
|
||||
|
||||
await GenOutboundMux(node, outbound, _config.CoreBasicItem.MuxEnabled);
|
||||
|
||||
if (node.StreamSecurity == Global.StreamSecurityReality || node.StreamSecurity == Global.StreamSecurity)
|
||||
if (node.Flow.IsNullOrEmpty())
|
||||
{
|
||||
if (Utils.IsNotEmpty(node.Flow))
|
||||
{
|
||||
usersItem.flow = node.Flow;
|
||||
|
||||
await GenOutboundMux(node, outbound, false);
|
||||
}
|
||||
await GenOutboundMux(node, outbound, muxEnabled, muxEnabled);
|
||||
}
|
||||
if (node.StreamSecurity == Global.StreamSecurityReality && Utils.IsNullOrEmpty(node.Flow))
|
||||
else
|
||||
{
|
||||
await GenOutboundMux(node, outbound, _config.CoreBasicItem.MuxEnabled);
|
||||
usersItem.flow = node.Flow;
|
||||
await GenOutboundMux(node, outbound, false, muxEnabled);
|
||||
}
|
||||
|
||||
outbound.settings.servers = null;
|
||||
break;
|
||||
}
|
||||
@@ -742,7 +734,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
serversItem.ota = false;
|
||||
serversItem.level = 1;
|
||||
|
||||
await GenOutboundMux(node, outbound, false);
|
||||
await GenOutboundMux(node, outbound);
|
||||
|
||||
outbound.settings.vnext = null;
|
||||
break;
|
||||
@@ -754,33 +746,35 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private async Task<int> GenOutboundMux(ProfileItem node, Outbounds4Ray outbound, bool enabled)
|
||||
private async Task<int> GenOutboundMux(ProfileItem node, Outbounds4Ray outbound, bool enabledTCP = false, bool enabledUDP = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (enabled)
|
||||
outbound.mux.enabled = false;
|
||||
outbound.mux.concurrency = -1;
|
||||
|
||||
if (enabledTCP)
|
||||
{
|
||||
outbound.mux.enabled = true;
|
||||
outbound.mux.concurrency = _config.Mux4RayItem.Concurrency;
|
||||
}
|
||||
else if (enabledUDP)
|
||||
{
|
||||
outbound.mux.enabled = true;
|
||||
outbound.mux.xudpConcurrency = _config.Mux4RayItem.XudpConcurrency;
|
||||
outbound.mux.xudpProxyUDP443 = _config.Mux4RayItem.XudpProxyUDP443;
|
||||
}
|
||||
else
|
||||
{
|
||||
outbound.mux.enabled = false;
|
||||
outbound.mux.concurrency = -1;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<int> GenBoundStreamSettings(ProfileItem node, Outbounds4Ray outbound)
|
||||
@@ -930,7 +924,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
|
||||
streamSettings.xhttpSettings = xhttpSettings;
|
||||
await GenOutboundMux(node, outbound, false);
|
||||
await GenOutboundMux(node, outbound);
|
||||
|
||||
break;
|
||||
//h2
|
||||
@@ -1020,7 +1014,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1040,9 +1034,13 @@ namespace ServiceLib.Services.CoreConfig
|
||||
//Outbound Freedom domainStrategy
|
||||
if (Utils.IsNotEmpty(domainStrategy4Freedom))
|
||||
{
|
||||
var outbound = v2rayConfig.outbounds[1];
|
||||
outbound.settings.domainStrategy = domainStrategy4Freedom;
|
||||
outbound.settings.userLevel = 0;
|
||||
var outbound = v2rayConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
|
||||
if (outbound != null)
|
||||
{
|
||||
outbound.settings = new();
|
||||
outbound.settings.domainStrategy = domainStrategy4Freedom;
|
||||
outbound.settings.userLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var obj = JsonUtils.ParseJson(normalDNS);
|
||||
@@ -1083,7 +1081,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1105,12 +1103,12 @@ namespace ServiceLib.Services.CoreConfig
|
||||
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<int> GenStatistic(V2rayConfig v2rayConfig)
|
||||
{
|
||||
if (_config.GuiItem.EnableStatistics)
|
||||
if (_config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
|
||||
{
|
||||
string tag = EInboundProtocol.api.ToString();
|
||||
Metrics4Ray apiObj = new();
|
||||
@@ -1152,7 +1150,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
v2rayConfig.routing.rules.Add(apiRoutingRule);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<int> GenMoreOutbounds(ProfileItem node, V2rayConfig v2rayConfig)
|
||||
@@ -1169,9 +1167,9 @@ namespace ServiceLib.Services.CoreConfig
|
||||
{
|
||||
fragment = new()
|
||||
{
|
||||
packets = "tlshello",
|
||||
length = "100-200",
|
||||
interval = "10-20"
|
||||
packets = _config.Fragment4RayItem?.Packets,
|
||||
length = _config.Fragment4RayItem?.Length,
|
||||
interval = _config.Fragment4RayItem?.Interval
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1241,7 +1239,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace ServiceLib.Services
|
||||
|
||||
public event ErrorEventHandler? Error;
|
||||
|
||||
private static readonly string _tag = "DownloadService";
|
||||
|
||||
public async Task<int> DownloadDataAsync(string url, WebProxy webProxy, int downloadTimeout, Action<bool, string> updateFunc)
|
||||
{
|
||||
try
|
||||
@@ -68,7 +70,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||
if (ex.InnerException != null)
|
||||
@@ -113,7 +115,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
@@ -131,7 +133,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
@@ -177,7 +179,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
@@ -208,7 +210,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
@@ -232,13 +234,13 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace ServiceLib.Services
|
||||
private Action<SpeedTestResult>? _updateFunc;
|
||||
|
||||
private bool _exitLoop = false;
|
||||
private static readonly string _tag = "SpeedtestService";
|
||||
|
||||
public SpeedtestService(Config config, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<SpeedTestResult> updateFunc)
|
||||
{
|
||||
@@ -146,7 +147,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -154,7 +155,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -201,7 +202,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -209,13 +210,13 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pid > 0)
|
||||
{
|
||||
await CoreHandler.Instance.CoreStopPid(pid);
|
||||
await ProcUtils.ProcessKill(pid);
|
||||
}
|
||||
await ProfileExHandler.Instance.SaveTo();
|
||||
}
|
||||
@@ -277,7 +278,7 @@ namespace ServiceLib.Services
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
await CoreHandler.Instance.CoreStopPid(pid);
|
||||
await ProcUtils.ProcessKill(pid);
|
||||
}
|
||||
await ProfileExHandler.Instance.SaveTo();
|
||||
}
|
||||
@@ -341,7 +342,7 @@ namespace ServiceLib.Services
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
await CoreHandler.Instance.CoreStopPid(pid);
|
||||
await ProcUtils.ProcessKill(pid);
|
||||
}
|
||||
await ProfileExHandler.Instance.SaveTo();
|
||||
}
|
||||
@@ -389,7 +390,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return responseTime;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace ServiceLib.Services.Statistics
|
||||
private ClientWebSocket? webSocket;
|
||||
private Action<ServerSpeedItem>? _updateFunc;
|
||||
private string Url => $"ws://{Global.Loopback}:{AppHandler.Instance.StatePort2}/traffic";
|
||||
private static readonly string _tag = "StatisticsSingboxService";
|
||||
|
||||
public StatisticsSingboxService(Config config, Action<ServerSpeedItem> updateFunc)
|
||||
{
|
||||
@@ -48,7 +49,7 @@ namespace ServiceLib.Services.Statistics
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace ServiceLib.Services
|
||||
{
|
||||
private Action<bool, string>? _updateFunc;
|
||||
private int _timeout = 30;
|
||||
private static readonly string _tag = "UpdateService";
|
||||
|
||||
public async Task CheckUpdateGuiN(Config config, Action<bool, string> updateFunc, bool preRelease)
|
||||
{
|
||||
@@ -272,7 +273,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
_updateFunc?.Invoke(false, ex.Message);
|
||||
return new RetResult(false, ex.Message);
|
||||
}
|
||||
@@ -356,7 +357,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
_updateFunc?.Invoke(false, ex.Message);
|
||||
return new SemanticVersion("");
|
||||
}
|
||||
@@ -415,7 +416,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
_updateFunc?.Invoke(false, ex.Message);
|
||||
return new RetResult(false, ex.Message);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace ServiceLib.ViewModels
|
||||
BrowseServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
_updateView?.Invoke(EViewAction.BrowseServer, null);
|
||||
await Task.CompletedTask;
|
||||
});
|
||||
EditServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
@@ -103,12 +104,13 @@ namespace ServiceLib.ViewModels
|
||||
address = Utils.GetConfigPath(address);
|
||||
if (File.Exists(address))
|
||||
{
|
||||
Utils.ProcessStart(address);
|
||||
ProcUtils.ProcessStart(address);
|
||||
}
|
||||
else
|
||||
{
|
||||
NoticeHandler.Instance.Enqueue(ResUI.FailedReadConfiguration);
|
||||
}
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,18 +130,31 @@ namespace ServiceLib.ViewModels
|
||||
DisplayOperationMsg(ResUI.LocalRestoreInvalidZipTips);
|
||||
return;
|
||||
}
|
||||
if (!Utils.UpgradeAppExists(out _))
|
||||
{
|
||||
DisplayOperationMsg(ResUI.UpgradeAppNotExistTip);
|
||||
return;
|
||||
}
|
||||
|
||||
//backup first
|
||||
var fileBackup = Utils.GetBackupPath(BackupFileName);
|
||||
var result = await CreateZipFileFromDirectory(fileBackup);
|
||||
if (result)
|
||||
{
|
||||
Locator.Current.GetService<MainWindowViewModel>()?.UpgradeApp(fileName);
|
||||
var service = Locator.Current.GetService<MainWindowViewModel>();
|
||||
await service?.MyAppExitAsync(true);
|
||||
await SQLiteHelper.Instance.DisposeDbConnectionAsync();
|
||||
|
||||
var toPath = Utils.GetConfigPath();
|
||||
FileManager.ZipExtractToFile(fileName, toPath, "");
|
||||
|
||||
if (Utils.IsWindows())
|
||||
{
|
||||
ProcUtils.RebootAsAdmin(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Utils.UpgradeAppExists(out var upgradeFileName))
|
||||
{
|
||||
ProcUtils.ProcessStart(upgradeFileName, Global.RebootAs, Utils.StartupPath());
|
||||
}
|
||||
}
|
||||
service?.Shutdown(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -160,10 +173,10 @@ namespace ServiceLib.ViewModels
|
||||
var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}");
|
||||
var configDirTemp = Path.Combine(configDirZipTemp, _guiConfigs);
|
||||
|
||||
FileManager.CopyDirectory(configDir, configDirTemp, false, "cache.db");
|
||||
FileManager.CopyDirectory(configDir, configDirTemp, false, true, "cache.db");
|
||||
var ret = FileManager.CreateFromDirectory(configDirZipTemp, fileName);
|
||||
Directory.Delete(configDirZipTemp, true);
|
||||
return ret;
|
||||
return await Task.FromResult(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,7 +248,7 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
foreach (var subDir in dir.GetDirectories())
|
||||
{
|
||||
FileManager.CopyDirectory(subDir.FullName, toPath, false, null);
|
||||
FileManager.CopyDirectory(subDir.FullName, toPath, false, true);
|
||||
subDir.Delete(true);
|
||||
}
|
||||
}
|
||||
@@ -259,7 +259,7 @@ namespace ServiceLib.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
FileManager.ZipExtractToFile(fileName, toPath, _config.GuiItem.IgnoreGeoUpdateCore ? "geo" : "");
|
||||
FileManager.ZipExtractToFile(fileName, toPath, "geo");
|
||||
}
|
||||
|
||||
if (Utils.IsNonWindows())
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace ServiceLib.ViewModels
|
||||
await ClashConnectionClose(true);
|
||||
});
|
||||
|
||||
Init();
|
||||
_ = Init();
|
||||
}
|
||||
|
||||
private async Task Init()
|
||||
@@ -73,6 +73,7 @@ namespace ServiceLib.ViewModels
|
||||
Task.Delay(1000).Wait();
|
||||
}
|
||||
});
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task GetClashConnections()
|
||||
|
||||
@@ -90,13 +90,13 @@ namespace ServiceLib.ViewModels
|
||||
y => y == true)
|
||||
.Subscribe(c => { _config.ClashUIItem.ProxiesAutoRefresh = AutoRefresh; });
|
||||
|
||||
Init();
|
||||
_ = Init();
|
||||
}
|
||||
|
||||
private async Task Init()
|
||||
{
|
||||
await ProxiesReload();
|
||||
DelayTestTask();
|
||||
_ = DelayTestTask();
|
||||
}
|
||||
|
||||
private async Task DoRulemodeSelected(bool c)
|
||||
@@ -265,7 +265,7 @@ namespace ServiceLib.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
_proxies.TryGetValue(name, out ProxiesItem proxy);
|
||||
_proxies.TryGetValue(name, out var proxy);
|
||||
if (proxy == null || proxy.all == null)
|
||||
{
|
||||
return;
|
||||
@@ -316,7 +316,7 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
if (_proxies is null)
|
||||
return null;
|
||||
_proxies.TryGetValue(name, out ProxiesItem proxy2);
|
||||
_proxies.TryGetValue(name, out var proxy2);
|
||||
if (proxy2 != null)
|
||||
{
|
||||
return proxy2;
|
||||
@@ -399,6 +399,7 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
_updateView?.Invoke(EViewAction.DispatcherProxiesDelayTest, new SpeedTestResult() { IndexId = item.Name, Delay = result });
|
||||
});
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void ProxiesDelayTestResult(SpeedTestResult result)
|
||||
@@ -434,7 +435,7 @@ namespace ServiceLib.ViewModels
|
||||
public async Task DelayTestTask()
|
||||
{
|
||||
var lastTime = DateTime.Now;
|
||||
Task.Run(async () =>
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
@@ -457,6 +458,7 @@ namespace ServiceLib.ViewModels
|
||||
lastTime = dtNow;
|
||||
}
|
||||
});
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion task
|
||||
|
||||
@@ -32,15 +32,17 @@ namespace ServiceLib.ViewModels
|
||||
ImportDefConfig4V2rayCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
normalDNS = Utils.GetEmbedText(Global.DNSV2rayNormalFileName);
|
||||
await Task.CompletedTask;
|
||||
});
|
||||
|
||||
ImportDefConfig4SingboxCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
normalDNS2 = Utils.GetEmbedText(Global.DNSSingboxNormalFileName);
|
||||
tunDNS2 = Utils.GetEmbedText(Global.TunSingboxDNSFileName);
|
||||
await Task.CompletedTask;
|
||||
});
|
||||
|
||||
Init();
|
||||
_ = Init();
|
||||
}
|
||||
|
||||
private async Task Init()
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using Splat;
|
||||
using System.Diagnostics;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace ServiceLib.ViewModels
|
||||
{
|
||||
@@ -50,6 +48,8 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
public ReactiveCommand<Unit, Unit> RegionalPresetRussiaCmd { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> RegionalPresetIranCmd { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> ReloadCmd { get; }
|
||||
|
||||
[Reactive]
|
||||
@@ -63,6 +63,8 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
#endregion Menu
|
||||
|
||||
private bool _hasNextReloadJob = false;
|
||||
|
||||
#region Init
|
||||
|
||||
public MainWindowViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
|
||||
@@ -197,9 +199,14 @@ namespace ServiceLib.ViewModels
|
||||
await ApplyRegionalPreset(EPresetType.Russia);
|
||||
});
|
||||
|
||||
RegionalPresetIranCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await ApplyRegionalPreset(EPresetType.Iran);
|
||||
});
|
||||
|
||||
#endregion WhenAnyValue && ReactiveCommand
|
||||
|
||||
Init();
|
||||
_ = Init();
|
||||
}
|
||||
|
||||
private async Task Init()
|
||||
@@ -212,11 +219,12 @@ namespace ServiceLib.ViewModels
|
||||
await CoreHandler.Instance.Init(_config, UpdateHandler);
|
||||
TaskHandler.Instance.RegUpdateTask(_config, UpdateTaskHandler);
|
||||
|
||||
if (_config.GuiItem.EnableStatistics)
|
||||
if (_config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
|
||||
{
|
||||
await StatisticsHandler.Instance.Init(_config, UpdateStatisticsHandler);
|
||||
}
|
||||
|
||||
BlReloadEnabled = true;
|
||||
await Reload();
|
||||
await AutoHideStartup();
|
||||
Locator.Current.GetService<StatusBarViewModel>()?.RefreshRoutingsMenu();
|
||||
@@ -244,7 +252,7 @@ namespace ServiceLib.ViewModels
|
||||
RefreshServers();
|
||||
if (indexIdOld != _config.IndexId)
|
||||
{
|
||||
Reload();
|
||||
_ = Reload();
|
||||
}
|
||||
if (_config.UiItem.EnableAutoAdjustMainLvColWidth)
|
||||
{
|
||||
@@ -264,17 +272,13 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
public void SetStatisticsResult(ServerSpeedItem update)
|
||||
{
|
||||
try
|
||||
if (_config.GuiItem.DisplayRealTimeSpeed)
|
||||
{
|
||||
Locator.Current.GetService<StatusBarViewModel>()?.UpdateStatistics(update);
|
||||
if ((update.ProxyUp + update.ProxyDown) > 0 && DateTime.Now.Second % 9 == 0)
|
||||
{
|
||||
Locator.Current.GetService<ProfilesViewModel>()?.UpdateStatistics(update);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
if (_config.GuiItem.EnableStatistics && (update.ProxyUp + update.ProxyDown) > 0 && DateTime.Now.Second % 9 == 0)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Locator.Current.GetService<ProfilesViewModel>()?.UpdateStatistics(update);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,34 +303,23 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
if (!blWindowsShutDown)
|
||||
{
|
||||
_updateView?.Invoke(EViewAction.Shutdown, null);
|
||||
_updateView?.Invoke(EViewAction.Shutdown, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpgradeApp(string arg)
|
||||
{
|
||||
if (!Utils.UpgradeAppExists(out var fileName))
|
||||
if (!Utils.UpgradeAppExists(out var upgradeFileName))
|
||||
{
|
||||
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.UpgradeAppNotExistTip);
|
||||
Logging.SaveLog("UpgradeApp does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
Process process = new()
|
||||
var id = ProcUtils.ProcessStart(upgradeFileName, arg, Utils.StartupPath());
|
||||
if (id > 0)
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
UseShellExecute = true,
|
||||
FileName = fileName,
|
||||
Arguments = arg.AppendQuotes(),
|
||||
WorkingDirectory = Utils.StartupPath()
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
if (process.Id > 0)
|
||||
{
|
||||
await MyAppExitAsync(false);
|
||||
await MyAppExitAsync(false);
|
||||
}
|
||||
}
|
||||
@@ -336,6 +329,11 @@ namespace ServiceLib.ViewModels
|
||||
_updateView?.Invoke(EViewAction.ShowHideWindow, blShow);
|
||||
}
|
||||
|
||||
public void Shutdown(bool byUser)
|
||||
{
|
||||
_updateView?.Invoke(EViewAction.Shutdown, byUser);
|
||||
}
|
||||
|
||||
#endregion Actions
|
||||
|
||||
#region Servers && Groups
|
||||
@@ -405,6 +403,7 @@ namespace ServiceLib.ViewModels
|
||||
public async Task AddServerViaScanAsync()
|
||||
{
|
||||
_updateView?.Invoke(EViewAction.ScanScreenTask, null);
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task ScanScreenResult(byte[]? bytes)
|
||||
@@ -416,6 +415,7 @@ namespace ServiceLib.ViewModels
|
||||
public async Task AddServerViaImageAsync()
|
||||
{
|
||||
_updateView?.Invoke(EViewAction.ScanImageTask, null);
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task ScanImageResult(string fileName)
|
||||
@@ -504,20 +504,8 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
public async Task RebootAsAdmin()
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessStartInfo startInfo = new()
|
||||
{
|
||||
UseShellExecute = true,
|
||||
Arguments = Global.RebootAs,
|
||||
WorkingDirectory = Utils.StartupPath(),
|
||||
FileName = Utils.GetExePath().AppendQuotes(),
|
||||
Verb = "runas",
|
||||
};
|
||||
Process.Start(startInfo);
|
||||
await MyAppExitAsync(false);
|
||||
}
|
||||
catch { }
|
||||
ProcUtils.RebootAsAdmin();
|
||||
await MyAppExitAsync(false);
|
||||
}
|
||||
|
||||
private async Task ClearServerStatistics()
|
||||
@@ -528,18 +516,20 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
private async Task OpenTheFileLocation()
|
||||
{
|
||||
var path = Utils.StartupPath();
|
||||
if (Utils.IsWindows())
|
||||
{
|
||||
Utils.ProcessStart("Explorer", $"/select,{Utils.GetConfigPath()}");
|
||||
ProcUtils.ProcessStart(path);
|
||||
}
|
||||
else if (Utils.IsLinux())
|
||||
{
|
||||
Utils.ProcessStart("nautilus", Utils.GetConfigPath());
|
||||
ProcUtils.ProcessStart("nautilus", path);
|
||||
}
|
||||
else if (Utils.IsOSX())
|
||||
{
|
||||
Utils.ProcessStart("open", Utils.GetConfigPath());
|
||||
ProcUtils.ProcessStart("open", path);
|
||||
}
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion Setting
|
||||
@@ -548,19 +538,33 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
public async Task Reload()
|
||||
{
|
||||
//If there are unfinished reload job, marked with next job.
|
||||
if (!BlReloadEnabled)
|
||||
{
|
||||
_hasNextReloadJob = true;
|
||||
return;
|
||||
}
|
||||
|
||||
BlReloadEnabled = false;
|
||||
|
||||
await LoadCore();
|
||||
Locator.Current.GetService<StatusBarViewModel>()?.TestServerAvailability();
|
||||
await SysProxyHandler.UpdateSysProxy(_config, false);
|
||||
Locator.Current.GetService<StatusBarViewModel>()?.TestServerAvailability();
|
||||
|
||||
_updateView?.Invoke(EViewAction.DispatcherReload, null);
|
||||
|
||||
BlReloadEnabled = true;
|
||||
if (_hasNextReloadJob)
|
||||
{
|
||||
_hasNextReloadJob = false;
|
||||
await Reload();
|
||||
}
|
||||
}
|
||||
|
||||
public void ReloadResult()
|
||||
{
|
||||
// BlReloadEnabled = true;
|
||||
//Locator.Current.GetService<StatusBarViewModel>()?.ChangeSystemProxyAsync(_config.systemProxyItem.sysProxyType, false);
|
||||
BlReloadEnabled = true;
|
||||
ShowClashUI = _config.IsRunningCore(ECoreType.sing_box);
|
||||
if (ShowClashUI)
|
||||
{
|
||||
@@ -571,16 +575,8 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
private async Task LoadCore()
|
||||
{
|
||||
//if (_config.tunModeItem.enableTun)
|
||||
//{
|
||||
// Task.Delay(1000).Wait();
|
||||
// WindowsUtils.RemoveTunDevice();
|
||||
//}
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var node = await ConfigHandler.GetDefaultServer(_config);
|
||||
await CoreHandler.Instance.LoadCore(node);
|
||||
});
|
||||
var node = await ConfigHandler.GetDefaultServer(_config);
|
||||
await CoreHandler.Instance.LoadCore(node);
|
||||
}
|
||||
|
||||
public async Task CloseCore()
|
||||
@@ -595,6 +591,7 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
ShowHideWindow(false);
|
||||
}
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion core job
|
||||
|
||||
@@ -59,14 +59,14 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_blLockShow = true;
|
||||
if (!_config.UiItem.ShowInTaskbar)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Delay(100);
|
||||
_blLockShow = true;
|
||||
|
||||
await Task.Delay(500);
|
||||
var txt = string.Join("", _queueMsg.ToArray());
|
||||
await _updateView?.Invoke(EViewAction.DispatcherShowMsg, txt);
|
||||
|
||||
@@ -105,6 +105,7 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
_queueMsg.Enqueue(Environment.NewLine);
|
||||
}
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void ClearMsg()
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace ServiceLib.ViewModels
|
||||
[Reactive] public bool AutoRun { get; set; }
|
||||
[Reactive] public bool EnableStatistics { get; set; }
|
||||
[Reactive] public bool KeepOlderDedupl { get; set; }
|
||||
[Reactive] public bool IgnoreGeoUpdateCore { get; set; }
|
||||
[Reactive] public bool DisplayRealTimeSpeed { get; set; }
|
||||
[Reactive] public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
||||
[Reactive] public bool EnableUpdateSubOnlyRemarksExist { get; set; }
|
||||
[Reactive] public bool EnableSecurityProtocolTls13 { get; set; }
|
||||
@@ -115,7 +115,7 @@ namespace ServiceLib.ViewModels
|
||||
await SaveSettingAsync();
|
||||
});
|
||||
|
||||
Init();
|
||||
_ = Init();
|
||||
}
|
||||
|
||||
private async Task Init()
|
||||
@@ -164,8 +164,8 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
AutoRun = _config.GuiItem.AutoRun;
|
||||
EnableStatistics = _config.GuiItem.EnableStatistics;
|
||||
DisplayRealTimeSpeed = _config.GuiItem.DisplayRealTimeSpeed;
|
||||
KeepOlderDedupl = _config.GuiItem.KeepOlderDedupl;
|
||||
IgnoreGeoUpdateCore = _config.GuiItem.IgnoreGeoUpdateCore;
|
||||
EnableAutoAdjustMainLvColWidth = _config.UiItem.EnableAutoAdjustMainLvColWidth;
|
||||
EnableUpdateSubOnlyRemarksExist = _config.UiItem.EnableUpdateSubOnlyRemarksExist;
|
||||
EnableSecurityProtocolTls13 = _config.GuiItem.EnableSecurityProtocolTls13;
|
||||
@@ -261,6 +261,7 @@ namespace ServiceLib.ViewModels
|
||||
break;
|
||||
}
|
||||
});
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task SaveSettingAsync()
|
||||
@@ -272,6 +273,7 @@ namespace ServiceLib.ViewModels
|
||||
return;
|
||||
}
|
||||
var needReboot = (EnableStatistics != _config.GuiItem.EnableStatistics
|
||||
|| DisplayRealTimeSpeed != _config.GuiItem.DisplayRealTimeSpeed
|
||||
|| EnableDragDropSort != _config.UiItem.EnableDragDropSort
|
||||
|| EnableHWA != _config.GuiItem.EnableHWA
|
||||
|| CurrentFontFamily != _config.UiItem.CurrentFontFamily
|
||||
@@ -317,8 +319,8 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
_config.GuiItem.AutoRun = AutoRun;
|
||||
_config.GuiItem.EnableStatistics = EnableStatistics;
|
||||
_config.GuiItem.DisplayRealTimeSpeed = DisplayRealTimeSpeed;
|
||||
_config.GuiItem.KeepOlderDedupl = KeepOlderDedupl;
|
||||
_config.GuiItem.IgnoreGeoUpdateCore = IgnoreGeoUpdateCore;
|
||||
_config.UiItem.EnableAutoAdjustMainLvColWidth = EnableAutoAdjustMainLvColWidth;
|
||||
_config.UiItem.EnableUpdateSubOnlyRemarksExist = EnableUpdateSubOnlyRemarksExist;
|
||||
_config.GuiItem.EnableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
|
||||
@@ -410,6 +412,7 @@ namespace ServiceLib.ViewModels
|
||||
}
|
||||
item.CoreType = (ECoreType)Enum.Parse(typeof(ECoreType), type);
|
||||
}
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,7 +231,7 @@ namespace ServiceLib.ViewModels
|
||||
MessageBus.Current.Listen<string>(EMsgCommand.RefreshProfiles.ToString()).Subscribe(OnNext);
|
||||
}
|
||||
|
||||
Init();
|
||||
_ = Init();
|
||||
}
|
||||
|
||||
private async Task Init()
|
||||
@@ -360,7 +360,7 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
public async Task RefreshServersBiz()
|
||||
{
|
||||
var lstModel = await AppHandler.Instance.ProfileItemsEx(_config.SubIndexId, _serverFilter);
|
||||
var lstModel = await GetProfileItemsEx(_config.SubIndexId, _serverFilter);
|
||||
_lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel)) ?? [];
|
||||
|
||||
_profileItems.Clear();
|
||||
@@ -399,6 +399,45 @@ namespace ServiceLib.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<ProfileItemModel>?> GetProfileItemsEx(string subid, string filter)
|
||||
{
|
||||
var lstModel = await AppHandler.Instance.ProfileItems(_config.SubIndexId, filter);
|
||||
|
||||
await ConfigHandler.SetDefaultServer(_config, lstModel);
|
||||
|
||||
var lstServerStat = (_config.GuiItem.EnableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
|
||||
var lstProfileExs = await ProfileExHandler.Instance.GetProfileExs();
|
||||
lstModel = (from t in lstModel
|
||||
join t2 in lstServerStat on t.IndexId equals t2.IndexId into t2b
|
||||
from t22 in t2b.DefaultIfEmpty()
|
||||
join t3 in lstProfileExs on t.IndexId equals t3.IndexId into t3b
|
||||
from t33 in t3b.DefaultIfEmpty()
|
||||
select new ProfileItemModel
|
||||
{
|
||||
IndexId = t.IndexId,
|
||||
ConfigType = t.ConfigType,
|
||||
Remarks = t.Remarks,
|
||||
Address = t.Address,
|
||||
Port = t.Port,
|
||||
Security = t.Security,
|
||||
Network = t.Network,
|
||||
StreamSecurity = t.StreamSecurity,
|
||||
Subid = t.Subid,
|
||||
SubRemarks = t.SubRemarks,
|
||||
IsActive = t.IndexId == _config.IndexId,
|
||||
Sort = t33 == null ? 0 : t33.Sort,
|
||||
Delay = t33 == null ? 0 : t33.Delay,
|
||||
DelayVal = t33?.Delay != 0 ? $"{t33?.Delay} {Global.DelayUnit}" : string.Empty,
|
||||
SpeedVal = t33?.Speed != 0 ? $"{t33?.Speed} {Global.SpeedUnit}" : string.Empty,
|
||||
TodayDown = t22 == null ? "" : Utils.HumanFy(t22.TodayDown),
|
||||
TodayUp = t22 == null ? "" : Utils.HumanFy(t22.TodayUp),
|
||||
TotalDown = t22 == null ? "" : Utils.HumanFy(t22.TotalDown),
|
||||
TotalUp = t22 == null ? "" : Utils.HumanFy(t22.TotalUp)
|
||||
}).OrderBy(t => t.Sort).ToList();
|
||||
|
||||
return lstModel;
|
||||
}
|
||||
|
||||
#endregion Servers && Groups
|
||||
|
||||
#region Add Servers
|
||||
|
||||
@@ -74,15 +74,16 @@ namespace ServiceLib.ViewModels
|
||||
SelectedSource.Protocol = ProtocolItems?.ToList();
|
||||
SelectedSource.InboundTag = InboundTagItems?.ToList();
|
||||
|
||||
bool hasRule = SelectedSource.Domain?.Count > 0
|
||||
var hasRule = SelectedSource.Domain?.Count > 0
|
||||
|| SelectedSource.Ip?.Count > 0
|
||||
|| SelectedSource.Protocol?.Count > 0
|
||||
|| SelectedSource.Process?.Count > 0
|
||||
|| Utils.IsNotEmpty(SelectedSource.Port);
|
||||
|| Utils.IsNotEmpty(SelectedSource.Port)
|
||||
|| Utils.IsNotEmpty(SelectedSource.Network);
|
||||
|
||||
if (!hasRule)
|
||||
{
|
||||
NoticeHandler.Instance.Enqueue(string.Format(ResUI.RoutingRuleDetailRequiredTips, "Port/Protocol/Domain/IP/Process"));
|
||||
NoticeHandler.Instance.Enqueue(string.Format(ResUI.RoutingRuleDetailRequiredTips, "Network/Port/Protocol/Domain/IP/Process"));
|
||||
return;
|
||||
}
|
||||
//NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using System.Reactive;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ServiceLib.ViewModels
|
||||
{
|
||||
@@ -177,19 +179,25 @@ namespace ServiceLib.ViewModels
|
||||
}
|
||||
|
||||
var lst = new List<RulesItem>();
|
||||
foreach (var it in SelectedSources ?? [SelectedSource])
|
||||
var sources = SelectedSources ?? [SelectedSource];
|
||||
foreach (var it in _rules)
|
||||
{
|
||||
var item = _rules.FirstOrDefault(t => t.Id == it?.Id);
|
||||
if (item != null)
|
||||
if (sources.Any(t => t.Id == it?.Id))
|
||||
{
|
||||
var item2 = JsonUtils.DeepCopy(item); //JsonUtils.Deserialize<RulesItem4Ray>(JsonUtils.Serialize(item));
|
||||
var item2 = JsonUtils.DeepCopy(it);
|
||||
item2.Id = null;
|
||||
lst.Add(item2 ?? new());
|
||||
}
|
||||
}
|
||||
if (lst.Count > 0)
|
||||
{
|
||||
await _updateView?.Invoke(EViewAction.SetClipboardData, JsonUtils.Serialize(lst));
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
};
|
||||
await _updateView?.Invoke(EViewAction.SetClipboardData, JsonUtils.Serialize(lst, options));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +257,7 @@ namespace ServiceLib.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
string result = Utils.LoadResource(fileName);
|
||||
var result = Utils.LoadResource(fileName);
|
||||
if (Utils.IsNullOrEmpty(result))
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace ServiceLib.ViewModels
|
||||
await SaveRoutingAsync();
|
||||
});
|
||||
|
||||
Init();
|
||||
_ = Init();
|
||||
}
|
||||
|
||||
private async Task Init()
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace ServiceLib.ViewModels
|
||||
public ReactiveCommand<Unit, Unit> AddServerViaScanCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SubUpdateCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SubUpdateViaProxyCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> CopyProxyCmdToClipboardCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> NotifyLeftClickCmd { get; }
|
||||
|
||||
#region System Proxy
|
||||
@@ -48,18 +49,6 @@ namespace ServiceLib.ViewModels
|
||||
[Reactive]
|
||||
public bool BlSystemProxyPac { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool BlNotSystemProxyClear { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool BlNotSystemProxySet { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool BlNotSystemProxyNothing { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool BlNotSystemProxyPac { get; set; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> SystemProxyClearCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SystemProxySetCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SystemProxyNothingCmd { get; }
|
||||
@@ -140,9 +129,15 @@ namespace ServiceLib.ViewModels
|
||||
y => y == true)
|
||||
.Subscribe(async c => await DoEnableTun(c));
|
||||
|
||||
CopyProxyCmdToClipboardCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await CopyProxyCmdToClipboard();
|
||||
});
|
||||
|
||||
NotifyLeftClickCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
Locator.Current.GetService<MainWindowViewModel>()?.ShowHideWindow(null);
|
||||
await Task.CompletedTask;
|
||||
});
|
||||
|
||||
AddServerViaClipboardCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
@@ -186,7 +181,7 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
InitUpdateView(updateView);
|
||||
}
|
||||
Init();
|
||||
_ = Init();
|
||||
}
|
||||
|
||||
private async Task Init()
|
||||
@@ -210,6 +205,23 @@ namespace ServiceLib.ViewModels
|
||||
await _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null);
|
||||
}
|
||||
|
||||
private async Task CopyProxyCmdToClipboard()
|
||||
{
|
||||
var cmd = Utils.IsWindows() ? "set" : "export";
|
||||
var address = $"{Global.Loopback}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)}";
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"{cmd} http_proxy={Global.HttpProtocol}{address}");
|
||||
sb.AppendLine($"{cmd} https_proxy={Global.HttpProtocol}{address}");
|
||||
sb.AppendLine($"{cmd} all_proxy={Global.Socks5Protocol}{address}");
|
||||
sb.AppendLine("");
|
||||
sb.AppendLine($"{cmd} HTTP_PROXY={Global.HttpProtocol}{address}");
|
||||
sb.AppendLine($"{cmd} HTTPS_PROXY={Global.HttpProtocol}{address}");
|
||||
sb.AppendLine($"{cmd} ALL_PROXY={Global.Socks5Protocol}{address}");
|
||||
|
||||
await _updateView?.Invoke(EViewAction.SetClipboardData, sb.ToString());
|
||||
}
|
||||
|
||||
private async Task AddServerViaClipboard()
|
||||
{
|
||||
var service = Locator.Current.GetService<MainWindowViewModel>();
|
||||
@@ -333,11 +345,6 @@ namespace ServiceLib.ViewModels
|
||||
BlSystemProxyNothing = (type == ESysProxyType.Unchanged);
|
||||
BlSystemProxyPac = (type == ESysProxyType.Pac);
|
||||
|
||||
BlNotSystemProxyClear = !BlSystemProxyClear;
|
||||
BlNotSystemProxySet = !BlSystemProxySet;
|
||||
BlNotSystemProxyNothing = !BlSystemProxyNothing;
|
||||
BlNotSystemProxyPac = !BlSystemProxyPac;
|
||||
|
||||
if (blChange)
|
||||
{
|
||||
_updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null);
|
||||
@@ -417,10 +424,12 @@ namespace ServiceLib.ViewModels
|
||||
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
|
||||
return;
|
||||
}
|
||||
//else if (Utils.IsLinux())
|
||||
//{
|
||||
// NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
|
||||
//}
|
||||
else if (Utils.IsOSX())
|
||||
{
|
||||
_config.TunModeItem.EnableTun = false;
|
||||
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
|
||||
return;
|
||||
}
|
||||
}
|
||||
await ConfigHandler.SaveConfig(_config);
|
||||
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
|
||||
@@ -470,12 +479,19 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
InboundLanDisplay = $"{ResUI.LabLAN}:{Global.None}";
|
||||
}
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void UpdateStatistics(ServerSpeedItem update)
|
||||
{
|
||||
SpeedProxyDisplay = string.Format(ResUI.SpeedDisplayText, Global.ProxyTag, Utils.HumanFy(update.ProxyUp), Utils.HumanFy(update.ProxyDown));
|
||||
SpeedDirectDisplay = string.Format(ResUI.SpeedDisplayText, Global.DirectTag, Utils.HumanFy(update.DirectUp), Utils.HumanFy(update.DirectDown));
|
||||
try
|
||||
{
|
||||
SpeedProxyDisplay = string.Format(ResUI.SpeedDisplayText, Global.ProxyTag, Utils.HumanFy(update.ProxyUp), Utils.HumanFy(update.ProxyDown));
|
||||
SpeedDirectDisplay = string.Format(ResUI.SpeedDisplayText, Global.DirectTag, Utils.HumanFy(update.DirectUp), Utils.HumanFy(update.DirectDown));
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endregion UI
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace ServiceLib.ViewModels
|
||||
await _updateView?.Invoke(EViewAction.ShareSub, SelectedSource?.Url);
|
||||
}, canEditRemove);
|
||||
|
||||
Init();
|
||||
_ = Init();
|
||||
}
|
||||
|
||||
private async Task Init()
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo 'Building Linux'
|
||||
|
||||
OutputPath='./bin/v2rayN'
|
||||
OutputPath64="${OutputPath}/linux-x64"
|
||||
OutputPathArm64="${OutputPath}/linux-arm64"
|
||||
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPath64
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPathArm64
|
||||
|
||||
rm -rf "$OutputPath64/*.pdb"
|
||||
rm -rf "$OutputPathArm64/*.pdb"
|
||||
|
||||
echo 'Build done'
|
||||
|
||||
7z a v2rayN-linux.zip $OutputPath
|
||||
exit 0
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo 'Building macOS'
|
||||
|
||||
OutputPath='./bin/v2rayN'
|
||||
OutputPath64="${OutputPath}/osx-x64"
|
||||
OutputPathArm64="${OutputPath}/osx-arm64"
|
||||
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPath64
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPathArm64
|
||||
|
||||
rm -rf "$OutputPath64/*.pdb"
|
||||
rm -rf "$OutputPathArm64/*.pdb"
|
||||
|
||||
echo 'Build done'
|
||||
|
||||
7z a v2rayN-osx.zip $OutputPath
|
||||
exit 0
|
||||
@@ -1,42 +0,0 @@
|
||||
param (
|
||||
[Parameter()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$OutputPathWin64 = './bin/v2rayN/win-x64',
|
||||
$OutputPathWinArm64 = './bin/v2rayN/win-arm64'
|
||||
)
|
||||
|
||||
Write-Host 'Building Windows'
|
||||
|
||||
dotnet publish `
|
||||
./v2rayN/v2rayN.csproj `
|
||||
-c Release `
|
||||
-r win-x64 `
|
||||
--self-contained false `
|
||||
-p:PublishReadyToRun=false `
|
||||
-p:PublishSingleFile=true `
|
||||
-o $OutputPathWin64
|
||||
|
||||
dotnet publish `
|
||||
./v2rayN/v2rayN.csproj `
|
||||
-c Release `
|
||||
-r win-arm64 `
|
||||
--self-contained false `
|
||||
-p:PublishReadyToRun=false `
|
||||
-p:PublishSingleFile=true `
|
||||
-o $OutputPathWinArm64
|
||||
|
||||
if ( -Not $? ) {
|
||||
exit $lastExitCode
|
||||
}
|
||||
|
||||
if ( Test-Path -Path ./bin/v2rayN ) {
|
||||
rm -Force "$OutputPathWin64/*.pdb"
|
||||
rm -Force "$OutputPathWinArm64/*.pdb"
|
||||
}
|
||||
|
||||
Write-Host 'Build done'
|
||||
|
||||
7z a v2rayN-windows-64.zip $OutputPathWin64
|
||||
7z a v2rayN-windows-arm64.zip $OutputPathWinArm64
|
||||
exit 0
|
||||
@@ -3,12 +3,13 @@
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:semi="https://irihi.tech/semi"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
x:DataType="vms:StatusBarViewModel"
|
||||
RequestedThemeVariant="Default">
|
||||
<Application.Styles>
|
||||
<semi:SemiTheme />
|
||||
<StyleInclude Source="Assets/GlobalStyles.axaml" />
|
||||
<StyleInclude Source="avares://Semi.Avalonia/Themes/Index.axaml" />
|
||||
<StyleInclude Source="avares://Semi.Avalonia.DataGrid/Index.axaml" />
|
||||
<StyleInclude Source="avares://DialogHost.Avalonia/Styles.xaml" />
|
||||
</Application.Styles>
|
||||
@@ -31,38 +32,26 @@
|
||||
<NativeMenuItem
|
||||
Command="{Binding SystemProxyClearCmd}"
|
||||
Header="{x:Static resx:ResUI.menuSystemProxyClear}"
|
||||
IsVisible="{Binding BlNotSystemProxyClear}" />
|
||||
<NativeMenuItem
|
||||
Command="{Binding SystemProxyClearCmd}"
|
||||
Header="{x:Static resx:ResUI.menuSystemProxyClear}"
|
||||
Icon="/Assets/NotifyIcon1.ico"
|
||||
IsVisible="{Binding BlSystemProxyClear}" />
|
||||
|
||||
IsChecked="{Binding BlSystemProxyClear}"
|
||||
ToggleType="Radio" />
|
||||
<NativeMenuItem
|
||||
Command="{Binding SystemProxySetCmd}"
|
||||
Header="{x:Static resx:ResUI.menuSystemProxySet}"
|
||||
IsVisible="{Binding BlNotSystemProxySet}" />
|
||||
<NativeMenuItem
|
||||
Command="{Binding SystemProxySetCmd}"
|
||||
Header="{x:Static resx:ResUI.menuSystemProxySet}"
|
||||
Icon="/Assets/NotifyIcon2.ico"
|
||||
IsVisible="{Binding BlSystemProxySet}" />
|
||||
|
||||
IsChecked="{Binding BlSystemProxySet}"
|
||||
ToggleType="Radio" />
|
||||
<NativeMenuItem
|
||||
Command="{Binding SystemProxyNothingCmd}"
|
||||
Header="{x:Static resx:ResUI.menuSystemProxyNothing}"
|
||||
IsVisible="{Binding BlNotSystemProxyNothing}" />
|
||||
<NativeMenuItem
|
||||
Command="{Binding SystemProxyNothingCmd}"
|
||||
Header="{x:Static resx:ResUI.menuSystemProxyNothing}"
|
||||
Icon="/Assets/NotifyIcon3.ico"
|
||||
IsVisible="{Binding BlSystemProxyNothing}" />
|
||||
IsChecked="{Binding BlSystemProxyNothing}"
|
||||
ToggleType="Radio" />
|
||||
<NativeMenuItemSeparator />
|
||||
<NativeMenuItem Click="MenuAddServerViaClipboardClick" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" />
|
||||
<NativeMenuItem Header="{x:Static resx:ResUI.menuAddServerViaScan}" IsVisible="False" />
|
||||
<NativeMenuItem Command="{Binding SubUpdateCmd}" Header="{x:Static resx:ResUI.menuSubUpdate}" />
|
||||
<NativeMenuItem Command="{Binding SubUpdateViaProxyCmd}" Header="{x:Static resx:ResUI.menuSubUpdateViaProxy}" />
|
||||
<NativeMenuItemSeparator />
|
||||
<NativeMenuItem Command="{Binding CopyProxyCmdToClipboardCmd}" Header="{x:Static resx:ResUI.menuCopyProxyCmdToClipboard}" />
|
||||
<NativeMenuItemSeparator />
|
||||
<NativeMenuItem Command="{Binding NotifyLeftClickCmd}" Header="{x:Static resx:ResUI.menuShowOrHideMainWindow}" />
|
||||
<NativeMenuItem Click="MenuExit_Click" Header="{x:Static resx:ResUI.menuExit}" />
|
||||
</NativeMenu>
|
||||
|
||||
@@ -71,12 +71,8 @@ public partial class App : Application
|
||||
|
||||
private async void MenuExit_Click(object? sender, EventArgs e)
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
var service = Locator.Current.GetService<MainWindowViewModel>();
|
||||
if (service != null) await service.MyAppExitAsync(false);
|
||||
|
||||
desktop.Shutdown();
|
||||
}
|
||||
var service = Locator.Current.GetService<MainWindowViewModel>();
|
||||
if (service != null) await service.MyAppExitAsync(true);
|
||||
service?.Shutdown(true);
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,12 @@ namespace v2rayN.Desktop.Common
|
||||
public static WindowIcon GetAppIcon(ESysProxyType sysProxyType)
|
||||
{
|
||||
var index = (int)sysProxyType + 1;
|
||||
var fileName = Utils.GetPath($"NotifyIcon{index}.ico");
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
return new(fileName);
|
||||
}
|
||||
|
||||
var uri = new Uri(Path.Combine(Global.AvaAssets, $"NotifyIcon{index}.ico"));
|
||||
using var bitmap = new Bitmap(AssetLoader.Open(uri));
|
||||
return new(bitmap);
|
||||
|
||||
@@ -17,13 +17,11 @@ namespace v2rayN.Desktop.Common
|
||||
|
||||
public static async Task<string?> OpenFileDialog(Window owner, FilePickerFileType? filter)
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(owner);
|
||||
if (topLevel == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var sp = GetStorageProvider(owner);
|
||||
if (sp is null) return null;
|
||||
|
||||
// Start async operation to open the dialog.
|
||||
var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||
var files = await sp.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
AllowMultiple = false,
|
||||
FileTypeFilter = filter is null ? [FilePickerFileTypes.All, FilePickerFileTypes.ImagePng] : [filter]
|
||||
@@ -34,17 +32,21 @@ namespace v2rayN.Desktop.Common
|
||||
|
||||
public static async Task<string?> SaveFileDialog(Window owner, string filter)
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(owner);
|
||||
if (topLevel == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var sp = GetStorageProvider(owner);
|
||||
if (sp is null) return null;
|
||||
|
||||
// Start async operation to open the dialog.
|
||||
var files = await topLevel.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
|
||||
var files = await sp.SaveFilePickerAsync(new FilePickerSaveOptions
|
||||
{
|
||||
});
|
||||
|
||||
return files?.TryGetLocalPath();
|
||||
}
|
||||
|
||||
private static IStorageProvider? GetStorageProvider(Window owner)
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(owner);
|
||||
return topLevel?.StorageProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,14 @@ using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using Semi.Avalonia;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace v2rayN.Desktop.ViewModels
|
||||
{
|
||||
public class ThemeSettingViewModel : MyReactiveObject
|
||||
{
|
||||
[Reactive] public bool ColorModeDark { get; set; }
|
||||
[Reactive] public bool FollowSystemTheme { get; set; }
|
||||
[Reactive] public string CurrentTheme { get; set; }
|
||||
|
||||
[Reactive] public int CurrentFontSize { get; set; }
|
||||
|
||||
@@ -31,32 +31,21 @@ namespace v2rayN.Desktop.ViewModels
|
||||
{
|
||||
ModifyTheme();
|
||||
ModifyFontFamily();
|
||||
ModifyFontSize();
|
||||
}
|
||||
|
||||
private void BindingUI()
|
||||
{
|
||||
ColorModeDark = _config.UiItem.ColorModeDark;
|
||||
FollowSystemTheme = _config.UiItem.FollowSystemTheme;
|
||||
CurrentTheme = _config.UiItem.CurrentTheme;
|
||||
CurrentFontSize = _config.UiItem.CurrentFontSize;
|
||||
CurrentLanguage = _config.UiItem.CurrentLanguage;
|
||||
|
||||
this.WhenAnyValue(x => x.ColorModeDark)
|
||||
this.WhenAnyValue(x => x.CurrentTheme)
|
||||
.Subscribe(c =>
|
||||
{
|
||||
if (_config.UiItem.ColorModeDark != ColorModeDark)
|
||||
if (_config.UiItem.CurrentTheme != CurrentTheme)
|
||||
{
|
||||
_config.UiItem.ColorModeDark = ColorModeDark;
|
||||
ModifyTheme();
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
this.WhenAnyValue(x => x.FollowSystemTheme,
|
||||
y => y == true)
|
||||
.Subscribe(c =>
|
||||
{
|
||||
if (_config.UiItem.FollowSystemTheme != FollowSystemTheme)
|
||||
{
|
||||
_config.UiItem.FollowSystemTheme = FollowSystemTheme;
|
||||
_config.UiItem.CurrentTheme = CurrentTheme;
|
||||
ModifyTheme();
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
@@ -67,11 +56,10 @@ namespace v2rayN.Desktop.ViewModels
|
||||
y => y > 0)
|
||||
.Subscribe(c =>
|
||||
{
|
||||
if (CurrentFontSize >= Global.MinFontSize)
|
||||
if (_config.UiItem.CurrentFontSize != CurrentFontSize && CurrentFontSize >= Global.MinFontSize)
|
||||
{
|
||||
_config.UiItem.CurrentFontSize = CurrentFontSize;
|
||||
double size = CurrentFontSize;
|
||||
ModifyFontSize(size);
|
||||
ModifyFontSize();
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
@@ -96,12 +84,24 @@ namespace v2rayN.Desktop.ViewModels
|
||||
var app = Application.Current;
|
||||
if (app is not null)
|
||||
{
|
||||
app.RequestedThemeVariant = FollowSystemTheme ? ThemeVariant.Default : (ColorModeDark ? ThemeVariant.Dark : ThemeVariant.Light);
|
||||
app.RequestedThemeVariant = CurrentTheme switch
|
||||
{
|
||||
nameof(ETheme.Dark) => ThemeVariant.Dark,
|
||||
nameof(ETheme.Light) => ThemeVariant.Light,
|
||||
nameof(ETheme.Aquatic) => SemiTheme.Aquatic,
|
||||
nameof(ETheme.Desert) => SemiTheme.Desert,
|
||||
nameof(ETheme.Dusk) => SemiTheme.Dusk,
|
||||
nameof(ETheme.NightSky) => SemiTheme.NightSky,
|
||||
_ => ThemeVariant.Default,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void ModifyFontSize(double size)
|
||||
private void ModifyFontSize()
|
||||
{
|
||||
double size = CurrentFontSize;
|
||||
if (size < Global.MinFontSize) return;
|
||||
|
||||
Style style = new(x => Selectors.Or(
|
||||
x.OfType<Button>(),
|
||||
x.OfType<TextBox>(),
|
||||
|
||||
@@ -5,25 +5,28 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
x:DataType="vms:BackupAndRestoreViewModel"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Styles>
|
||||
<Style Selector="Button">
|
||||
<Setter Property="MinWidth" Value="180" />
|
||||
</Style>
|
||||
</UserControl.Styles>
|
||||
|
||||
<DockPanel Classes="Margin8">
|
||||
<DockPanel Classes="Margin8" DockPanel.Dock="Bottom">
|
||||
<StackPanel Classes="Margin8" DockPanel.Dock="Bottom">
|
||||
<TextBlock
|
||||
Name="txtMsg"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel>
|
||||
<Border
|
||||
Margin="4"
|
||||
VerticalAlignment="Center"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
Theme="{DynamicResource CardBorder}">
|
||||
|
||||
<Grid
|
||||
Classes="Margin8"
|
||||
@@ -49,7 +52,10 @@
|
||||
Classes="Margin8"
|
||||
Content="{x:Static resx:ResUI.menuLocalBackup}" />
|
||||
|
||||
<Separator Grid.Row="2" Grid.ColumnSpan="2" />
|
||||
<Separator
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
@@ -69,21 +75,21 @@
|
||||
<Border
|
||||
Margin="4"
|
||||
VerticalAlignment="Center"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
Theme="{DynamicResource CardBorder}">
|
||||
<Grid
|
||||
Classes="Margin8"
|
||||
ColumnDefinitions="300,200"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.menuRemoteBackupAndRestore}" />
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock Classes="Margin8" Text="{x:Static resx:ResUI.menuRemoteBackupAndRestore}" />
|
||||
|
||||
<Button
|
||||
Width="30"
|
||||
Height="30"
|
||||
MinWidth="30"
|
||||
Margin="10,0"
|
||||
Theme="{DynamicResource BorderlessButton}">
|
||||
<Button.Content>
|
||||
@@ -184,7 +190,10 @@
|
||||
Classes="Margin8"
|
||||
Content="{x:Static resx:ResUI.menuRemoteBackup}" />
|
||||
|
||||
<Separator Grid.Row="2" Grid.ColumnSpan="3" />
|
||||
<Separator
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2" />
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
|
||||
@@ -9,7 +9,12 @@ namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class BackupAndRestoreView : ReactiveUserControl<BackupAndRestoreViewModel>
|
||||
{
|
||||
private Window _window;
|
||||
private Window? _window;
|
||||
|
||||
public BackupAndRestoreView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public BackupAndRestoreView(Window window)
|
||||
{
|
||||
|
||||
@@ -35,11 +35,16 @@
|
||||
Content="{x:Static resx:ResUI.menuCheckUpdate}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel>
|
||||
<Border
|
||||
Margin="4"
|
||||
VerticalAlignment="Center"
|
||||
Theme="{DynamicResource CardBorder}">
|
||||
|
||||
<ListBox
|
||||
x:Name="lstCheckUpdates"
|
||||
BorderThickness="1"
|
||||
ItemsSource="{Binding CheckUpdateModels}">
|
||||
ItemsSource="{Binding CheckUpdateModels}"
|
||||
Theme="{StaticResource ButtonRadioGroupListBox}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical" />
|
||||
@@ -47,19 +52,14 @@
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border
|
||||
Width="500"
|
||||
Height="80"
|
||||
Margin="-8"
|
||||
VerticalAlignment="Center"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
<Panel Width="500" VerticalAlignment="Center">
|
||||
<Grid ColumnDefinitions="1*,1*,3*" RowDefinitions="Auto">
|
||||
<ToggleSwitch
|
||||
x:Name="togAutoRefresh"
|
||||
Grid.Column="0"
|
||||
Margin="8"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
VerticalAlignment="Center"
|
||||
IsChecked="{Binding IsSelected}" />
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
@@ -73,11 +73,10 @@
|
||||
Text="{Binding Remarks}"
|
||||
TextWrapping="WrapWithOverflow" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ListBox>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DockPanel>
|
||||
|
||||
</UserControl>
|
||||
@@ -28,7 +28,7 @@
|
||||
Text="{x:Static resx:ResUI.menuRulemode}" />
|
||||
<ComboBox
|
||||
x:Name="cmbRulemode"
|
||||
Width="80"
|
||||
Width="100"
|
||||
Margin="8,0">
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeRule}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeGlobal}" />
|
||||
@@ -41,7 +41,7 @@
|
||||
Text="{x:Static resx:ResUI.TbSorting}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSorting"
|
||||
Width="60"
|
||||
Width="100"
|
||||
Margin="8,0">
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDelay}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingName}" />
|
||||
@@ -95,7 +95,8 @@
|
||||
<ListBox
|
||||
x:Name="lstProxyGroups"
|
||||
DockPanel.Dock="Left"
|
||||
ItemsSource="{Binding ProxyGroups}">
|
||||
ItemsSource="{Binding ProxyGroups}"
|
||||
Theme="{StaticResource ButtonRadioGroupListBox}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical" />
|
||||
@@ -105,24 +106,25 @@
|
||||
<DataTemplate>
|
||||
<Border
|
||||
Width="160"
|
||||
Margin="-6"
|
||||
Margin="-8,-4"
|
||||
Padding="0"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
<DockPanel>
|
||||
<Grid Classes="Margin8" RowDefinitions="1*,8,1*">
|
||||
<DockPanel Grid.Row="0">
|
||||
<TextBlock DockPanel.Dock="Right" Text="{Binding Type}" />
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</DockPanel>
|
||||
<TextBlock Grid.Row="2" Text="{Binding Now}" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
<Grid Classes="Margin8" RowDefinitions="1*,8,1*">
|
||||
<DockPanel Grid.Row="0">
|
||||
<TextBlock DockPanel.Dock="Right" Text="{Binding Type}" />
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</DockPanel>
|
||||
<TextBlock Grid.Row="2" Text="{Binding Now}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<ListBox x:Name="lstProxyDetails" ItemsSource="{Binding ProxyDetails}">
|
||||
<ListBox
|
||||
x:Name="lstProxyDetails"
|
||||
ItemsSource="{Binding ProxyDetails}"
|
||||
Theme="{StaticResource ButtonRadioGroupListBox}">
|
||||
<ItemsControl.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem x:Name="menuProxiesDelaytestPart" Header="{x:Static resx:ResUI.menuProxiesDelaytestPart}" />
|
||||
@@ -138,7 +140,7 @@
|
||||
<DataTemplate>
|
||||
<Border
|
||||
Width="160"
|
||||
Margin="-6"
|
||||
Margin="-12,-4"
|
||||
Padding="0"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
<DockPanel>
|
||||
|
||||
@@ -65,12 +65,12 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
private void linkDnsObjectDoc_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart("https://xtls.github.io/config/dns.html#dnsobject");
|
||||
ProcUtils.ProcessStart("https://xtls.github.io/config/dns.html#dnsobject");
|
||||
}
|
||||
|
||||
private void linkDnsSingboxObjectDoc_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/dns/");
|
||||
ProcUtils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/dns/");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,7 @@
|
||||
<MenuItem Header="{x:Static resx:ResUI.menuRegionalPresets}">
|
||||
<MenuItem x:Name="menuRegionalPresetsDefault" Header="{x:Static resx:ResUI.menuRegionalPresetsDefault}" />
|
||||
<MenuItem x:Name="menuRegionalPresetsRussia" Header="{x:Static resx:ResUI.menuRegionalPresetsRussia}" />
|
||||
<MenuItem x:Name="menuRegionalPresetsIran" Header="{x:Static resx:ResUI.menuRegionalPresetsIran}" />
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuBackupAndRestore" Header="{x:Static resx:ResUI.menuBackupAndRestore}" />
|
||||
<MenuItem x:Name="menuOpenTheFileLocation" Header="{x:Static resx:ResUI.menuOpenTheFileLocation}" />
|
||||
@@ -149,71 +150,20 @@
|
||||
x:Name="tabMain1"
|
||||
Grid.Row="2"
|
||||
TabStripPlacement="Left">
|
||||
<TabItem x:Name="tabMsgView1">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.MsgInformationTitle}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="tabClashProxies1">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.TbProxies}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="tabClashConnections1">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.TbConnections}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="tabMsgView1" Header="{x:Static resx:ResUI.MsgInformationTitle}" />
|
||||
<TabItem x:Name="tabClashProxies1" Header="{x:Static resx:ResUI.TbProxies}" />
|
||||
<TabItem x:Name="tabClashConnections1" Header="{x:Static resx:ResUI.TbConnections}" />
|
||||
</TabControl>
|
||||
</Grid>
|
||||
<Grid x:Name="gridMain2" IsVisible="False">
|
||||
<TabControl x:Name="tabMain2" TabStripPlacement="Left">
|
||||
<TabItem x:Name="tabProfiles2">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.menuServers}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="tabMsgView2">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.MsgInformationTitle}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="tabClashProxies2">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.TbProxies}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="tabClashConnections2">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.TbConnections}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="tabProfiles2" Header="{x:Static resx:ResUI.menuServers}" />
|
||||
<TabItem x:Name="tabMsgView2" Header="{x:Static resx:ResUI.MsgInformationTitle}" />
|
||||
<TabItem x:Name="tabClashProxies2" Header="{x:Static resx:ResUI.TbProxies}" />
|
||||
<TabItem x:Name="tabClashConnections2" Header="{x:Static resx:ResUI.TbConnections}" />
|
||||
</TabControl>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</DockPanel>
|
||||
</dialogHost:DialogHost>
|
||||
</Window>
|
||||
@@ -104,6 +104,7 @@ namespace v2rayN.Desktop.Views
|
||||
this.BindCommand(ViewModel, vm => vm.OpenTheFileLocationCmd, v => v.menuOpenTheFileLocation).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RegionalPresetDefaultCmd, v => v.menuRegionalPresetsDefault).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RegionalPresetRussiaCmd, v => v.menuRegionalPresetsRussia).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RegionalPresetIranCmd, v => v.menuRegionalPresetsIran).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.BlReloadEnabled, v => v.menuReload.IsEnabled).DisposeWith(disposables);
|
||||
@@ -133,7 +134,7 @@ namespace v2rayN.Desktop.Views
|
||||
}
|
||||
});
|
||||
|
||||
this.Title = $"{Utils.GetVersion()} - {(AppHandler.Instance.IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
|
||||
this.Title = $"{Utils.GetVersion()}";
|
||||
if (Utils.IsWindows())
|
||||
{
|
||||
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
|
||||
@@ -222,6 +223,10 @@ namespace v2rayN.Desktop.Views
|
||||
break;
|
||||
|
||||
case EViewAction.Shutdown:
|
||||
if (obj != null && _blCloseByUser == false)
|
||||
{
|
||||
_blCloseByUser = (bool)obj;
|
||||
}
|
||||
StorageUI();
|
||||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
@@ -304,7 +309,7 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
private async void MainWindow_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyModifiers == KeyModifiers.Control)
|
||||
if (e.KeyModifiers is KeyModifiers.Control or KeyModifiers.Meta)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
@@ -329,12 +334,12 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
private void menuPromotion_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}");
|
||||
ProcUtils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}");
|
||||
}
|
||||
|
||||
private void menuSettingsSetUWP_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe"));
|
||||
ProcUtils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe"));
|
||||
}
|
||||
|
||||
public async Task ScanScreenTaskAsync()
|
||||
@@ -480,7 +485,7 @@ namespace v2rayN.Desktop.Views
|
||||
{
|
||||
if (sender is MenuItem item)
|
||||
{
|
||||
Utils.ProcessStart(item.Tag?.ToString());
|
||||
ProcUtils.ProcessStart(item.Tag?.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Left"
|
||||
IsChecked="True"
|
||||
Theme="{StaticResource SimpleToggleSwitch}" />
|
||||
Theme="{DynamicResource SimpleToggleSwitch}" />
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
@@ -75,7 +75,7 @@
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Left"
|
||||
IsChecked="True"
|
||||
Theme="{StaticResource SimpleToggleSwitch}" />
|
||||
Theme="{DynamicResource SimpleToggleSwitch}" />
|
||||
</WrapPanel>
|
||||
<TextBox
|
||||
Name="txtMsg"
|
||||
|
||||
@@ -114,8 +114,8 @@
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8"
|
||||
SelectionMode="Multiple"
|
||||
Theme="{DynamicResource PureCardRadioGroupListBox}" />
|
||||
SelectionMode="Multiple,Toggle"
|
||||
Theme="{DynamicResource CardCheckGroupListBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
@@ -385,9 +385,9 @@
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsKeepOlderDedupl}" />
|
||||
Text="{x:Static resx:ResUI.TbSettingsDisplayRealTimeSpeed}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togKeepOlderDedupl"
|
||||
x:Name="togDisplayRealTimeSpeed"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
@@ -398,9 +398,9 @@
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsIgnoreGeoUpdateCore}" />
|
||||
Text="{x:Static resx:ResUI.TbSettingsKeepOlderDedupl}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togIgnoreGeoUpdateCore"
|
||||
x:Name="togKeepOlderDedupl"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
@@ -714,102 +714,100 @@
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsTunMode}">
|
||||
<DockPanel Classes="Margin8">
|
||||
<Grid
|
||||
<Grid
|
||||
Classes="Margin8"
|
||||
ColumnDefinitions="Auto,Auto,Auto"
|
||||
DockPanel.Dock="Top"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
ColumnDefinitions="Auto,Auto,Auto"
|
||||
DockPanel.Dock="Top"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
Text="Strict Route" />
|
||||
<ToggleSwitch
|
||||
x:Name="togStrictRoute"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Strict Route" />
|
||||
<ToggleSwitch
|
||||
x:Name="togStrictRoute"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Stack" />
|
||||
<ComboBox
|
||||
x:Name="cmbStack"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Stack" />
|
||||
<ComboBox
|
||||
x:Name="cmbStack"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Mtu" />
|
||||
<ComboBox
|
||||
x:Name="cmbMtu"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Mtu" />
|
||||
<ComboBox
|
||||
x:Name="cmbMtu"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableExInbound}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableExInbound"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableExInbound}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableExInbound"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableIPv6Address}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableIPv6Address"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableIPv6Address}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableIPv6Address"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPassword}" />
|
||||
<TextBox
|
||||
x:Name="txtLinuxSudoPassword"
|
||||
Grid.Row="7"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPasswordTip}"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPassword}" />
|
||||
<TextBox
|
||||
x:Name="txtLinuxSudoPassword"
|
||||
Grid.Row="7"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPasswordTip}"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreType}">
|
||||
|
||||
@@ -126,8 +126,8 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableStatistics, v => v.togEnableStatistics.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.DisplayRealTimeSpeed, v => v.togDisplayRealTimeSpeed.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.KeepOlderDedupl, v => v.togKeepOlderDedupl.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.IgnoreGeoUpdateCore, v => v.togIgnoreGeoUpdateCore.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableAutoAdjustMainLvColWidth, v => v.togEnableAutoAdjustMainLvColWidth.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableUpdateSubOnlyRemarksExist, v => v.togEnableUpdateSubOnlyRemarksExist.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableSecurityProtocolTls13, v => v.togEnableSecurityProtocolTls13.IsChecked).DisposeWith(disposables);
|
||||
@@ -235,7 +235,7 @@ namespace v2rayN.Desktop.Views
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("fill fonts error", ex);
|
||||
Logging.SaveLog("GetFonts", ex);
|
||||
}
|
||||
return lstFonts;
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
Classes="Solid Red"
|
||||
Content="{x:Static resx:ResUI.TipActiveServer}"
|
||||
IsVisible="{Binding IsActive}"
|
||||
Theme="{StaticResource TagLabel}" />
|
||||
Theme="{DynamicResource TagLabel}" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
|
||||
@@ -15,7 +15,12 @@ namespace v2rayN.Desktop.Views
|
||||
public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||
{
|
||||
private static Config _config;
|
||||
private Window _window;
|
||||
private Window? _window;
|
||||
|
||||
public ProfilesView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public ProfilesView(Window window)
|
||||
{
|
||||
@@ -187,12 +192,7 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
private void lstProfiles_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
List<ProfileItemModel> lst = [];
|
||||
foreach (var item in lstProfiles.SelectedItems)
|
||||
{
|
||||
lst.Add((ProfileItemModel)item);
|
||||
}
|
||||
ViewModel.SelectedProfiles = lst;
|
||||
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
||||
}
|
||||
|
||||
private void LstProfiles_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
@@ -233,7 +233,7 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
private void LstProfiles_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyModifiers == KeyModifiers.Control)
|
||||
if (e.KeyModifiers is KeyModifiers.Control or KeyModifiers.Meta)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
d:DesignHeight="480"
|
||||
d:DesignWidth="400"
|
||||
mc:Ignorable="d">
|
||||
<Grid Margin="30" RowDefinitions="Auto,Auto">
|
||||
|
||||
<Image
|
||||
Name="imgQrcode"
|
||||
Width="300"
|
||||
@@ -24,6 +22,5 @@
|
||||
IsReadOnly="True"
|
||||
MaxLines="1" />
|
||||
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -5,6 +5,11 @@ namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class QrcodeView : UserControl
|
||||
{
|
||||
public QrcodeView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public QrcodeView(string? url)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
@@ -94,8 +94,8 @@
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8"
|
||||
SelectionMode="Multiple"
|
||||
Theme="{DynamicResource PureCardRadioGroupListBox}" />
|
||||
SelectionMode="Multiple,Toggle"
|
||||
Theme="{DynamicResource CardCheckGroupListBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
@@ -108,8 +108,8 @@
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Classes="Margin8"
|
||||
SelectionMode="Multiple"
|
||||
Theme="{DynamicResource PureCardRadioGroupListBox}" />
|
||||
SelectionMode="Multiple,Toggle"
|
||||
Theme="{DynamicResource CardCheckGroupListBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user