Compare commits
115 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
fe7314c978 | ||
|
|
d4eb8e59a6 | ||
|
|
8ee00907b7 | ||
|
|
25fddc3c71 | ||
|
|
c78b733850 | ||
|
|
a57c83125e | ||
|
|
247b59985f | ||
|
|
7470b8b6d3 | ||
|
|
776d37b7aa | ||
|
|
8f532f8468 | ||
|
|
472963fe2d | ||
|
|
6a9b62ab9a | ||
|
|
9ac8aa2969 | ||
|
|
838bd2c794 | ||
|
|
b2bbe432e0 | ||
|
|
b3d8042452 | ||
|
|
0c758a7fdc | ||
|
|
85cb1d1c92 | ||
|
|
2cd2e8894d | ||
|
|
abb58379b3 | ||
|
|
4f48e8b190 | ||
|
|
2b5cbb5e74 | ||
|
|
23dd140921 | ||
|
|
8c8d7bda64 | ||
|
|
a6e246948a | ||
|
|
c49ba735a0 | ||
|
|
1a33c598e8 | ||
|
|
a4bbdb49de | ||
|
|
cf3846fbfd | ||
|
|
d46943eedf | ||
|
|
3bc17bd50a | ||
|
|
48a159f4c8 | ||
|
|
3d1bcffdc5 | ||
|
|
45fa0f94d2 | ||
|
|
ed16b7de4a | ||
|
|
f2ec03c7ec | ||
|
|
11db87f1e6 | ||
|
|
a1feaf33e0 | ||
|
|
53a99e3f79 | ||
|
|
e7f04f55c2 | ||
|
|
6653ea12b7 | ||
|
|
a28cef5b98 | ||
|
|
78a28fbdb3 | ||
|
|
bf8bbbdcb0 | ||
|
|
83ad83b135 | ||
|
|
dbd4f55981 | ||
|
|
5f5d7172ee | ||
|
|
fbd4557b44 | ||
|
|
5d55a55754 | ||
|
|
84032aec33 | ||
|
|
a372d8902e | ||
|
|
c38c62e4c3 | ||
|
|
8aceff7480 | ||
|
|
736c450161 | ||
|
|
3b63a3d308 | ||
|
|
4f56174c8f | ||
|
|
4d2eb324f1 | ||
|
|
3f2ab8ddcb | ||
|
|
fd8f863c5b | ||
|
|
246f1d7df0 | ||
|
|
ccacda9bf5 | ||
|
|
5494d63878 | ||
|
|
c32b9812a7 | ||
|
|
9eb9898b61 | ||
|
|
834e05999f | ||
|
|
b4c37d9906 | ||
|
|
9326b450d7 | ||
|
|
019ee8b1ba | ||
|
|
f043645397 | ||
|
|
3b173f0b3e | ||
|
|
f36c06389d | ||
|
|
d3a0b44247 | ||
|
|
e4d3a98aa8 | ||
|
|
f685682214 | ||
|
|
1c6323315b | ||
|
|
1ff4839be1 | ||
|
|
558e5bb340 | ||
|
|
48a9d208e6 |
77
.github/workflows/build-linux.yml
vendored
Normal file
77
.github/workflows/build-linux.yml
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
name: release Linux
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
required: false
|
||||
type: string
|
||||
push:
|
||||
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:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Release]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd v2rayN
|
||||
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: |
|
||||
${{ 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
|
||||
62
.github/workflows/build-osx.yml
vendored
62
.github/workflows/build-osx.yml
vendored
@@ -1,10 +1,20 @@
|
||||
name: release macos
|
||||
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:
|
||||
@@ -19,14 +29,50 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
run: cd v2rayN &&
|
||||
./build-osx.sh
|
||||
run: |
|
||||
cd v2rayN
|
||||
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
|
||||
68
.github/workflows/build-windows.yml
vendored
Normal file
68
.github/workflows/build-windows.yml
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
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: 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 "windows-64-With-Core" $OutputPath64
|
||||
./package-release-zip.sh $OutputArchArm $OutputPathArm64
|
||||
./package-release-zip.sh "windows-64-SelfContained" $OutputPath64Sc
|
||||
./package-release-zip.sh "windows-64-SelfContained-With-Core" $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
|
||||
60
.github/workflows/build.yml
vendored
60
.github/workflows/build.yml
vendored
@@ -1,60 +0,0 @@
|
||||
name: release
|
||||
|
||||
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: 删除工作流运行
|
||||
# uses: Mattraks/delete-workflow-runs@v2
|
||||
# with:
|
||||
# token: ${{ github.token }}
|
||||
# repository: ${{ github.repository }}
|
||||
# retain_days: 0
|
||||
# keep_minimum_runs: 1
|
||||
|
||||
- name: Build
|
||||
run: cd v2rayN &&
|
||||
./build.ps1
|
||||
|
||||
# - name: Package
|
||||
# shell: pwsh
|
||||
# run: |
|
||||
# 7z a -mx9 ..\v2rayN.7z $env:Wap_Project_Directory
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: v2rayN
|
||||
path: |
|
||||
./v2rayN/v2rayN.zip
|
||||
|
||||
# - name: Release
|
||||
# uses: softprops/action-gh-release@v1
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
# with:
|
||||
# prerelease: ${{ contains(github.ref, '-') }}
|
||||
# draft: false
|
||||
# files: |
|
||||
# .\v2rayN\v2rayN.zip
|
||||
# body: |
|
||||
# [](https://t.me/netch_channel) [](https://t.me/netch_group)
|
||||
# ## Changelogs
|
||||
# * This is an automated deployment of GitHub Actions, the change log should be updated manually soon
|
||||
|
||||
# ## 更新日志
|
||||
# * 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新
|
||||
31
.github/workflows/winget-publish.yml
vendored
Normal file
31
.github/workflows/winget-publish.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: WinGet submission on release
|
||||
# based off of https://github.com/nushell/nushell/blob/main/.github/workflows/winget-submission.yml
|
||||
# inspired by https://github.com/microsoft/PowerToys/blob/main/.github/workflows/package-submissions.yml
|
||||
# Modified by @MerrickZ https://github.com/anpho
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
jobs:
|
||||
winget:
|
||||
name: Publish winget package
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Submit v2ray package to Windows Package Manager Community Repository
|
||||
run: |
|
||||
|
||||
$wingetPackage = "2dust.v2rayN"
|
||||
$gitToken = "${{ secrets.PT_WINGET }}"
|
||||
|
||||
$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
|
||||
|
||||
$ver = $targetRelease.tag_name
|
||||
|
||||
# getting latest wingetcreate file
|
||||
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
||||
.\wingetcreate.exe update $wingetPackage -s -v $ver -u "$installerUrl|x64" -t $gitToken
|
||||
@@ -1,5 +1,5 @@
|
||||
# v2rayN
|
||||
A GUI client for Windows and Linux, support [Xray core](https://github.com/XTLS/Xray-core) 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)
|
||||
@@ -13,12 +13,17 @@ Check [Release files introduction](https://github.com/2dust/v2rayN/wiki/Release-
|
||||
### Windows
|
||||
- Run `v2rayN.exe`
|
||||
### Linux
|
||||
- `chmod +x v2rayN` Run `./v2rayN`
|
||||
- `chmod +x v2rayN` Run `./v2rayN` under user permissions
|
||||
```
|
||||
Debian 9+
|
||||
Ubuntu 16.04+
|
||||
Fedora 30+
|
||||
```
|
||||
### macOS
|
||||
- `chmod +x v2rayN` Run `./v2rayN` under user permissions
|
||||
```
|
||||
macOS 10.14+
|
||||
```
|
||||
|
||||
## Requirements
|
||||
- [Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
|
||||
|
||||
53
package-debian.sh
Normal file
53
package-debian.sh
Normal file
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
|
||||
Arch="$1"
|
||||
OutputPath="$2"
|
||||
Version="$3"
|
||||
|
||||
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"
|
||||
65
package-osx.sh
Executable file
65
package-osx.sh
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/bin/bash
|
||||
|
||||
Arch="$1"
|
||||
OutputPath="$2"
|
||||
Version="$3"
|
||||
|
||||
PackagePath="v2rayN-Package-${Arch}"
|
||||
mkdir -p "$PackagePath/v2rayN.app/Contents/Resources"
|
||||
cp -rf "$OutputPath" "$PackagePath/v2rayN.app/Contents/MacOS"
|
||||
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"
|
||||
|
||||
mkdir -p "$PackagePath/icons.iconset"
|
||||
sips -z 16 16 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN2.png" --out "$PackagePath/icons.iconset/icon_16x16.png"
|
||||
sips -z 32 32 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN2.png" --out "$PackagePath/icons.iconset/icon_16x16@2x.png"
|
||||
sips -z 32 32 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN2.png" --out "$PackagePath/icons.iconset/icon_32x32.png"
|
||||
sips -z 64 64 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN2.png" --out "$PackagePath/icons.iconset/icon_32x32@2x.png"
|
||||
sips -z 128 128 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN2.png" --out "$PackagePath/icons.iconset/icon_128x128.png"
|
||||
sips -z 256 256 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN2.png" --out "$PackagePath/icons.iconset/icon_128x128@2x.png"
|
||||
sips -z 256 256 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN2.png" --out "$PackagePath/icons.iconset/icon_256x256.png"
|
||||
sips -z 512 512 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN2.png" --out "$PackagePath/icons.iconset/icon_256x256@2x.png"
|
||||
sips -z 512 512 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN2.png" --out "$PackagePath/icons.iconset/icon_512x512.png"
|
||||
sips -z 1024 1024 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN2.png" --out "$PackagePath/icons.iconset/icon_512x512@2x.png"
|
||||
iconutil -c icns "$PackagePath/icons.iconset" -o "$PackagePath/v2rayN.app/Contents/Resources/AppIcon.icns"
|
||||
|
||||
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
|
||||
@@ -6,7 +6,7 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
|
||||
<FileVersion>1.3.0</FileVersion>
|
||||
<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);
|
||||
Waiting(3);
|
||||
|
||||
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,7 +42,7 @@ namespace AmazTool
|
||||
StringBuilder sb = new();
|
||||
try
|
||||
{
|
||||
string thisAppOldFile = $"{GetExePath()}.tmp";
|
||||
string thisAppOldFile = $"{Utils.GetExePath()}.tmp";
|
||||
File.Delete(thisAppOldFile);
|
||||
string splitKey = "/";
|
||||
|
||||
@@ -62,12 +62,12 @@ namespace AmazTool
|
||||
if (lst.Length == 1) continue;
|
||||
string 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);
|
||||
string entryOutputPath = Utils.GetPath(fullName);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
||||
entry.ExtractToFile(entryOutputPath, true);
|
||||
|
||||
@@ -91,40 +91,12 @@ namespace AmazTool
|
||||
}
|
||||
|
||||
Console.WriteLine(Resx.Resource.Restartv2rayN);
|
||||
Waiting(9);
|
||||
Process process = new()
|
||||
{
|
||||
StartInfo = new()
|
||||
{
|
||||
UseShellExecute = true,
|
||||
FileName = V2rayN,
|
||||
WorkingDirectory = StartupPath()
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
Waiting(2);
|
||||
|
||||
Utils.StartV2RayN();
|
||||
}
|
||||
|
||||
private static string GetExePath()
|
||||
{
|
||||
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
|
||||
}
|
||||
|
||||
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)
|
||||
public static void Waiting(int second)
|
||||
{
|
||||
for (var i = second; i > 0; i--)
|
||||
{
|
||||
@@ -132,7 +104,5 @@ namespace AmazTool
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
private static string V2rayN => "v2rayN";
|
||||
}
|
||||
}
|
||||
43
v2rayN/AmazTool/Utils.cs
Normal file
43
v2rayN/AmazTool/Utils.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,7 +150,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace ServiceLib.Common
|
||||
{
|
||||
private static readonly Lazy<HttpClientHelper> _instance = new(() =>
|
||||
{
|
||||
HttpClientHandler handler = new() { UseCookies = false };
|
||||
SocketsHttpHandler handler = new() { UseCookies = false };
|
||||
HttpClientHelper helper = new(new HttpClient(handler));
|
||||
return helper;
|
||||
});
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace ServiceLib.Common
|
||||
{
|
||||
public class JsonUtils
|
||||
{
|
||||
private static readonly string _tag = "JsonUtils";
|
||||
|
||||
/// <summary>
|
||||
/// DeepCopy
|
||||
/// </summary>
|
||||
@@ -70,8 +72,9 @@ namespace ServiceLib.Common
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="indented"></param>
|
||||
/// <param name="nullValue"></param>
|
||||
/// <returns></returns>
|
||||
public static string Serialize(object? obj, bool indented = true)
|
||||
public static string Serialize(object? obj, bool indented = true, bool nullValue = false)
|
||||
{
|
||||
var result = string.Empty;
|
||||
try
|
||||
@@ -82,14 +85,14 @@ namespace ServiceLib.Common
|
||||
}
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = indented ? true : false,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||
WriteIndented = indented,
|
||||
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
|
||||
};
|
||||
result = JsonSerializer.Serialize(obj, options);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -100,38 +103,5 @@ namespace ServiceLib.Common
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj);
|
||||
|
||||
/// <summary>
|
||||
/// Save as json file
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="nullValue"></param>
|
||||
/// <returns></returns>
|
||||
public static int ToFile(object? obj, string? filePath, bool nullValue = true)
|
||||
{
|
||||
if (filePath is null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
try
|
||||
{
|
||||
using var file = File.Create(filePath);
|
||||
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
|
||||
};
|
||||
|
||||
JsonSerializer.Serialize(file, obj, options);
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
105
v2rayN/ServiceLib/Common/ProcUtils.cs
Normal file
105
v2rayN/ServiceLib/Common/ProcUtils.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
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;
|
||||
}
|
||||
|
||||
var fileName = review ? proc?.MainModule?.FileName : null;
|
||||
var processName = review ? proc?.ProcessName : null;
|
||||
|
||||
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);
|
||||
if (review && fileName != null)
|
||||
{
|
||||
var proc2 = Process.GetProcessesByName(processName)
|
||||
.FirstOrDefault(t => t.MainModule?.FileName == fileName);
|
||||
if (proc2 != null)
|
||||
{
|
||||
Logging.SaveLog($"{_tag}, KillProcess not completing the job");
|
||||
await ProcessKill(proc2, false);
|
||||
proc2 = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ServiceLib.Common
|
||||
{
|
||||
public static class QueryableExtension
|
||||
{
|
||||
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> query, string propertyName)
|
||||
{
|
||||
return _OrderBy<T>(query, propertyName, false);
|
||||
}
|
||||
|
||||
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> query, string propertyName)
|
||||
{
|
||||
return _OrderBy<T>(query, propertyName, true);
|
||||
}
|
||||
|
||||
private static IOrderedQueryable<T> _OrderBy<T>(IQueryable<T> query, string propertyName, bool isDesc)
|
||||
{
|
||||
var methodname = (isDesc) ? "OrderByDescendingInternal" : "OrderByInternal";
|
||||
|
||||
var memberProp = typeof(T).GetProperty(propertyName);
|
||||
|
||||
var method = typeof(QueryableExtension).GetMethod(methodname)
|
||||
.MakeGenericMethod(typeof(T), memberProp.PropertyType);
|
||||
|
||||
return (IOrderedQueryable<T>)method.Invoke(null, new object[] { query, memberProp });
|
||||
}
|
||||
|
||||
public static IOrderedQueryable<T> OrderByInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
|
||||
{//public
|
||||
return query.OrderBy(_GetLambda<T, TProp>(memberProperty));
|
||||
}
|
||||
|
||||
public static IOrderedQueryable<T> OrderByDescendingInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
|
||||
{//public
|
||||
return query.OrderByDescending(_GetLambda<T, TProp>(memberProperty));
|
||||
}
|
||||
|
||||
private static Expression<Func<T, TProp>> _GetLambda<T, TProp>(PropertyInfo memberProperty)
|
||||
{
|
||||
if (memberProperty.PropertyType != typeof(TProp)) throw new Exception();
|
||||
|
||||
var thisArg = Expression.Parameter(typeof(T));
|
||||
var lambda = Expression.Lambda<Func<T, TProp>>(Expression.Property(thisArg, memberProperty), thisArg);
|
||||
|
||||
return lambda;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,8 @@
|
||||
var parts = this.version.Split('.');
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
this.major = int.Parse(parts[0]);
|
||||
this.minor = int.Parse(parts[1]);
|
||||
this.major = int.Parse(parts.First());
|
||||
this.minor = int.Parse(parts.Last());
|
||||
this.patch = 0;
|
||||
}
|
||||
else if (parts.Length is 3 or 4)
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ namespace ServiceLib.Common
|
||||
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
|
||||
{
|
||||
if (s.IsNullOrEmpty()) return false;
|
||||
return chars.Contains(s[0]);
|
||||
return chars.Contains(s.First());
|
||||
}
|
||||
|
||||
private static bool IsWhiteSpace(this string value)
|
||||
@@ -61,7 +61,7 @@ namespace ServiceLib.Common
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return char.ToUpper(value[0]) + value[1..];
|
||||
return char.ToUpper(value.First()) + value[1..];
|
||||
}
|
||||
|
||||
public static string AppendQuotes(this string value)
|
||||
|
||||
@@ -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;
|
||||
@@ -313,8 +315,8 @@ namespace ServiceLib.Common
|
||||
continue;
|
||||
}
|
||||
|
||||
var key = Uri.UnescapeDataString(keyValue[0]);
|
||||
var val = Uri.UnescapeDataString(keyValue[1]);
|
||||
var key = Uri.UnescapeDataString(keyValue.First());
|
||||
var val = Uri.UnescapeDataString(keyValue.Last());
|
||||
|
||||
if (result[key] is null)
|
||||
{
|
||||
@@ -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(AppDomain.CurrentDomain.BaseDirectory, GetExeName("AmazTool"));
|
||||
return File.Exists(upgradeFileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -529,19 +531,13 @@ namespace ServiceLib.Common
|
||||
{
|
||||
try
|
||||
{
|
||||
if (blFull)
|
||||
{
|
||||
return
|
||||
$"{Global.AppName} - V{GetVersionInfo()} - {RuntimeInformation.ProcessArchitecture} - {File.GetLastWriteTime(GetExePath()):yyyy/MM/dd}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{Global.AppName}/{GetVersionInfo()}";
|
||||
}
|
||||
return blFull
|
||||
? $"{Global.AppName} - V{GetVersionInfo()} - {RuntimeInformation.ProcessArchitecture}"
|
||||
: $"{Global.AppName}/{GetVersionInfo()}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return Global.AppName;
|
||||
@@ -555,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} | {(Environment.Is64BitOperatingSystem ? 64 : 32)}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取得GUID
|
||||
/// </summary>
|
||||
@@ -579,7 +580,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
@@ -590,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>();
|
||||
@@ -622,14 +606,14 @@ namespace ServiceLib.Common
|
||||
{
|
||||
if (host.StartsWith("#")) continue;
|
||||
var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (hostItem.Length < 2) continue;
|
||||
systemHosts.Add(hostItem[1], hostItem[0]);
|
||||
if (hostItem.Length != 2) continue;
|
||||
systemHosts.Add(hostItem.Last(), hostItem.First());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return systemHosts;
|
||||
@@ -677,6 +661,33 @@ namespace ServiceLib.Common
|
||||
|
||||
#region TempPath
|
||||
|
||||
public static bool HasWritePermission()
|
||||
{
|
||||
try
|
||||
{
|
||||
//When this file exists, it is equivalent to having no permission to read and write
|
||||
if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "NotStoreConfigHere.txt")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "guiTemps");
|
||||
if (!Directory.Exists(tempPath))
|
||||
{
|
||||
Directory.CreateDirectory(tempPath);
|
||||
}
|
||||
var fileName = Path.Combine(tempPath, GetGuid());
|
||||
File.Create(fileName).Close();
|
||||
File.Delete(fileName);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string GetPath(string fileName)
|
||||
{
|
||||
var startupPath = StartupPath();
|
||||
@@ -695,6 +706,11 @@ namespace ServiceLib.Common
|
||||
|
||||
public static string StartupPath()
|
||||
{
|
||||
if (Utils.IsNonWindows() && Environment.GetEnvironmentVariable("V2RAYN_LOCAL_APPLICATION_DATA") == "1")
|
||||
{
|
||||
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "v2rayN");
|
||||
}
|
||||
|
||||
return AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
|
||||
@@ -818,6 +834,8 @@ namespace ServiceLib.Common
|
||||
|
||||
public static bool IsOSX() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
|
||||
public static bool IsNonWindows() => !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
|
||||
public static string GetExeName(string name)
|
||||
{
|
||||
return IsWindows() ? $"{name}.exe" : name;
|
||||
@@ -829,18 +847,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()
|
||||
@@ -852,6 +871,8 @@ 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);
|
||||
}
|
||||
@@ -870,6 +891,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,7 @@ 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 +16,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -41,7 +42,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
v2fly = 1,
|
||||
Xray = 2,
|
||||
v2fly_v5 = 4,
|
||||
|
||||
mihomo = 13,
|
||||
|
||||
hysteria = 21,
|
||||
naiveproxy = 22,
|
||||
tuic = 23,
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
public enum EInboundProtocol
|
||||
{
|
||||
socks = 0,
|
||||
http,
|
||||
socks2,
|
||||
http2,
|
||||
socks3,
|
||||
pac,
|
||||
api,
|
||||
api2,
|
||||
mixed,
|
||||
speedtest = 21
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
SendMsgView,
|
||||
SendSnackMsg,
|
||||
RefreshProfiles,
|
||||
StopSpeedtest
|
||||
StopSpeedtest,
|
||||
AppExit
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,6 @@
|
||||
{
|
||||
Default = 0,
|
||||
Russia = 1,
|
||||
Iran = 2,
|
||||
}
|
||||
}
|
||||
@@ -68,15 +68,17 @@
|
||||
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||
public const string AutoRunName = "v2rayNAutoRun";
|
||||
public const string CustomIconName = "v2rayN.ico";
|
||||
public const string IEProxyExceptions = "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 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 RoutingRuleComma = "<COMMA>";
|
||||
public const string GrpcGunMode = "gun";
|
||||
public const string GrpcMultiMode = "multi";
|
||||
public const int MaxPort = 65536;
|
||||
public const string DelayUnit = "";
|
||||
public const string SpeedUnit = "";
|
||||
public const int MinFontSize = 10;
|
||||
public const int MinFontSize = 8;
|
||||
public const string RebootAs = "rebootas";
|
||||
public const string AvaAssets = "avares://v2rayN/Assets/";
|
||||
|
||||
public static readonly List<string> IEProxyProtocols = new() {
|
||||
"{ip}:{http_port}",
|
||||
@@ -122,21 +124,25 @@
|
||||
public static readonly List<string> GeoFilesSources = new() {
|
||||
"",
|
||||
@"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() {
|
||||
"",
|
||||
@"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() {
|
||||
"",
|
||||
@"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() {
|
||||
"",
|
||||
@"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()
|
||||
@@ -182,24 +188,23 @@
|
||||
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() { "v2fly", "Xray", "sing_box" };
|
||||
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
|
||||
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" };
|
||||
public static readonly List<string> XhttpMode = new() { "auto", "packet-up", "stream-up", "stream-one" };
|
||||
|
||||
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" };
|
||||
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", "http", "socks2", "http2" };
|
||||
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"];
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
get
|
||||
{
|
||||
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
|
||||
return _statePort2.Value;
|
||||
return _statePort2.Value + (_config.TunModeItem.EnableTun ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,11 +46,18 @@
|
||||
|
||||
public bool InitApp()
|
||||
{
|
||||
_config = ConfigHandler.LoadConfig();
|
||||
if (_config == null)
|
||||
if (Utils.IsNonWindows() && Utils.HasWritePermission() == false)
|
||||
{
|
||||
Environment.SetEnvironmentVariable("V2RAYN_LOCAL_APPLICATION_DATA", "1", EnvironmentVariableTarget.Process);
|
||||
}
|
||||
|
||||
Logging.Setup();
|
||||
var config = ConfigHandler.LoadConfig();
|
||||
if (config == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_config = config;
|
||||
Thread.CurrentThread.CurrentUICulture = new(_config.UiItem.CurrentLanguage);
|
||||
|
||||
//Under Win10
|
||||
@@ -70,15 +77,20 @@
|
||||
|
||||
public bool InitComponents()
|
||||
{
|
||||
Logging.Setup();
|
||||
Logging.SaveLog($"v2rayN start up | {Utils.GetRuntimeInfo()}");
|
||||
Logging.LoggingEnabled(_config.GuiItem.EnableLog);
|
||||
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
||||
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||
Logging.ClearLogs();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Reset()
|
||||
{
|
||||
_statePort = null;
|
||||
_statePort2 = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Config
|
||||
@@ -257,16 +269,8 @@
|
||||
return (ECoreType)profileItem.CoreType;
|
||||
}
|
||||
|
||||
if (_config.CoreTypeItem == null)
|
||||
{
|
||||
return ECoreType.Xray;
|
||||
}
|
||||
var item = _config.CoreTypeItem.FirstOrDefault(it => it.ConfigType == eConfigType);
|
||||
if (item == null)
|
||||
{
|
||||
return ECoreType.Xray;
|
||||
}
|
||||
return item.CoreType;
|
||||
var item = _config.CoreTypeItem?.FirstOrDefault(it => it.ConfigType == eConfigType);
|
||||
return item?.CoreType ?? ECoreType.Xray;
|
||||
}
|
||||
|
||||
#endregion Core Type
|
||||
|
||||
@@ -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())
|
||||
@@ -25,7 +27,7 @@ namespace ServiceLib.Handler
|
||||
await SetTaskLinux();
|
||||
}
|
||||
}
|
||||
else if(Utils.IsOSX())
|
||||
else if (Utils.IsOSX())
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
@@ -62,7 +64,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +125,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +145,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,7 +9,7 @@ namespace ServiceLib.Handler
|
||||
public class ConfigHandler
|
||||
{
|
||||
private static readonly string _configRes = Global.ConfigFileName;
|
||||
private static readonly object _objLock = new();
|
||||
private static readonly string _tag = "ConfigHandler";
|
||||
|
||||
#region ConfigHandler
|
||||
|
||||
@@ -62,15 +62,14 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
if (config.Inbound.Count > 0)
|
||||
{
|
||||
config.Inbound[0].Protocol = EInboundProtocol.socks.ToString();
|
||||
config.Inbound.First().Protocol = EInboundProtocol.socks.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
config.RoutingBasicItem ??= new();
|
||||
|
||||
if (Utils.IsNullOrEmpty(config.RoutingBasicItem.DomainStrategy))
|
||||
{
|
||||
config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies[0];//"IPIfNonMatch";
|
||||
config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies.First();
|
||||
}
|
||||
|
||||
config.KcpItem ??= new KcpItem
|
||||
@@ -111,7 +110,7 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
if (Thread.CurrentThread.CurrentCulture.Name.Equals("zh-cn", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
config.UiItem.CurrentLanguage = Global.Languages[0];
|
||||
config.UiItem.CurrentLanguage = Global.Languages.First();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -120,10 +119,6 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
|
||||
config.ConstItem ??= new ConstItem();
|
||||
if (Utils.IsNullOrEmpty(config.ConstItem.DefIEProxyExceptions))
|
||||
{
|
||||
config.ConstItem.DefIEProxyExceptions = Global.IEProxyExceptions;
|
||||
}
|
||||
|
||||
config.SpeedTestItem ??= new();
|
||||
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
||||
@@ -132,7 +127,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(config.SpeedTestItem.SpeedTestUrl))
|
||||
{
|
||||
config.SpeedTestItem.SpeedTestUrl = Global.SpeedTestUrls[0];
|
||||
config.SpeedTestItem.SpeedTestUrl = Global.SpeedTestUrls.First();
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(config.SpeedTestItem.SpeedPingTestUrl))
|
||||
{
|
||||
@@ -148,7 +143,7 @@ namespace ServiceLib.Handler
|
||||
|
||||
config.Mux4SboxItem ??= new()
|
||||
{
|
||||
Protocol = Global.SingboxMuxs[0],
|
||||
Protocol = Global.SingboxMuxs.First(),
|
||||
MaxConnections = 8
|
||||
};
|
||||
|
||||
@@ -162,6 +157,16 @@ namespace ServiceLib.Handler
|
||||
config.WebDavItem ??= new();
|
||||
config.CheckUpdateItem ??= new();
|
||||
|
||||
if (Utils.IsNotEmpty(config.ConstItem.DefIEProxyExceptions))
|
||||
{
|
||||
config.SystemProxyItem.SystemProxyExceptions = $"{config.ConstItem.DefIEProxyExceptions};{config.SystemProxyItem.SystemProxyExceptions}";
|
||||
config.ConstItem.DefIEProxyExceptions = string.Empty;
|
||||
}
|
||||
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
|
||||
{
|
||||
config.SystemProxyItem.SystemProxyExceptions = Utils.IsWindows() ? Global.SystemProxyExceptionsWindows : Global.SystemProxyExceptionsLinux;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -172,30 +177,26 @@ namespace ServiceLib.Handler
|
||||
/// <returns></returns>
|
||||
public static async Task<int> SaveConfig(Config config)
|
||||
{
|
||||
lock (_objLock)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
//save temp file
|
||||
var resPath = Utils.GetConfigPath(_configRes);
|
||||
var tempPath = $"{resPath}_temp";
|
||||
if (JsonUtils.ToFile(config, tempPath) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
//save temp file
|
||||
var resPath = Utils.GetConfigPath(_configRes);
|
||||
var tempPath = $"{resPath}_temp";
|
||||
|
||||
if (File.Exists(resPath))
|
||||
{
|
||||
File.Delete(resPath);
|
||||
}
|
||||
//rename
|
||||
File.Move(tempPath, resPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
var content = JsonUtils.Serialize(config, true, true);
|
||||
if (content.IsNullOrEmpty())
|
||||
{
|
||||
Logging.SaveLog("ToJsonFile", ex);
|
||||
return -1;
|
||||
}
|
||||
await File.WriteAllTextAsync(tempPath, content);
|
||||
|
||||
//rename
|
||||
File.Move(tempPath, resPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -429,7 +430,7 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
sort = ProfileExHandler.Instance.GetSort(lstProfile[0].IndexId) - 1;
|
||||
sort = ProfileExHandler.Instance.GetSort(lstProfile.First().IndexId) - 1;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -500,7 +501,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -766,69 +767,66 @@ namespace ServiceLib.Handler
|
||||
}).ToList();
|
||||
|
||||
Enum.TryParse(colName, true, out EServerColName name);
|
||||
var propertyName = string.Empty;
|
||||
switch (name)
|
||||
{
|
||||
case EServerColName.ConfigType:
|
||||
case EServerColName.Remarks:
|
||||
case EServerColName.Address:
|
||||
case EServerColName.Port:
|
||||
case EServerColName.Network:
|
||||
case EServerColName.StreamSecurity:
|
||||
propertyName = name.ToString();
|
||||
break;
|
||||
|
||||
case EServerColName.DelayVal:
|
||||
propertyName = "Delay";
|
||||
break;
|
||||
|
||||
case EServerColName.SpeedVal:
|
||||
propertyName = "Speed";
|
||||
break;
|
||||
|
||||
case EServerColName.SubRemarks:
|
||||
propertyName = "Subid";
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
var items = lstProfile.AsQueryable();
|
||||
|
||||
if (asc)
|
||||
{
|
||||
lstProfile = items.OrderBy(propertyName).ToList();
|
||||
lstProfile = name switch
|
||||
{
|
||||
EServerColName.ConfigType => lstProfile.OrderBy(t => t.ConfigType).ToList(),
|
||||
EServerColName.Remarks => lstProfile.OrderBy(t => t.Remarks).ToList(),
|
||||
EServerColName.Address => lstProfile.OrderBy(t => t.Address).ToList(),
|
||||
EServerColName.Port => lstProfile.OrderBy(t => t.Port).ToList(),
|
||||
EServerColName.Network => lstProfile.OrderBy(t => t.Network).ToList(),
|
||||
EServerColName.StreamSecurity => lstProfile.OrderBy(t => t.StreamSecurity).ToList(),
|
||||
EServerColName.DelayVal => lstProfile.OrderBy(t => t.Delay).ToList(),
|
||||
EServerColName.SpeedVal => lstProfile.OrderBy(t => t.Speed).ToList(),
|
||||
EServerColName.SubRemarks => lstProfile.OrderBy(t => t.Subid).ToList(),
|
||||
_ => lstProfile
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
lstProfile = items.OrderByDescending(propertyName).ToList();
|
||||
lstProfile = name switch
|
||||
{
|
||||
EServerColName.ConfigType => lstProfile.OrderByDescending(t => t.ConfigType).ToList(),
|
||||
EServerColName.Remarks => lstProfile.OrderByDescending(t => t.Remarks).ToList(),
|
||||
EServerColName.Address => lstProfile.OrderByDescending(t => t.Address).ToList(),
|
||||
EServerColName.Port => lstProfile.OrderByDescending(t => t.Port).ToList(),
|
||||
EServerColName.Network => lstProfile.OrderByDescending(t => t.Network).ToList(),
|
||||
EServerColName.StreamSecurity => lstProfile.OrderByDescending(t => t.StreamSecurity).ToList(),
|
||||
EServerColName.DelayVal => lstProfile.OrderByDescending(t => t.Delay).ToList(),
|
||||
EServerColName.SpeedVal => lstProfile.OrderByDescending(t => t.Speed).ToList(),
|
||||
EServerColName.SubRemarks => lstProfile.OrderByDescending(t => t.Subid).ToList(),
|
||||
_ => lstProfile
|
||||
};
|
||||
}
|
||||
for (int i = 0; i < lstProfile.Count; i++)
|
||||
|
||||
for (var i = 0; i < lstProfile.Count; i++)
|
||||
{
|
||||
ProfileExHandler.Instance.SetSort(lstProfile[i].IndexId, (i + 1) * 10);
|
||||
}
|
||||
if (name == EServerColName.DelayVal)
|
||||
switch (name)
|
||||
{
|
||||
var maxSort = lstProfile.Max(t => t.Sort) + 10;
|
||||
foreach (var item in lstProfile)
|
||||
{
|
||||
if (item.Delay <= 0)
|
||||
case EServerColName.DelayVal:
|
||||
{
|
||||
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
|
||||
var maxSort = lstProfile.Max(t => t.Sort) + 10;
|
||||
foreach (var item in lstProfile.Where(item => item.Delay <= 0))
|
||||
{
|
||||
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (name == EServerColName.SpeedVal)
|
||||
{
|
||||
var maxSort = lstProfile.Max(t => t.Sort) + 10;
|
||||
foreach (var item in lstProfile)
|
||||
{
|
||||
if (item.Speed <= 0)
|
||||
case EServerColName.SpeedVal:
|
||||
{
|
||||
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
|
||||
var maxSort = lstProfile.Max(t => t.Sort) + 10;
|
||||
foreach (var item in lstProfile.Where(item => item.Speed <= 0))
|
||||
{
|
||||
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -990,7 +988,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("Remove Item", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1029,12 +1027,11 @@ namespace ServiceLib.Handler
|
||||
public static async Task<ProfileItem?> GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType)
|
||||
{
|
||||
ProfileItem? itemSocks = null;
|
||||
var preCoreType = ECoreType.sing_box;
|
||||
if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && config.TunModeItem.EnableTun)
|
||||
{
|
||||
itemSocks = new ProfileItem()
|
||||
{
|
||||
CoreType = preCoreType,
|
||||
CoreType = ECoreType.sing_box,
|
||||
ConfigType = EConfigType.SOCKS,
|
||||
Address = Global.Loopback,
|
||||
Sni = node.Address, //Tun2SocksAddress
|
||||
@@ -1043,7 +1040,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
else if ((node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0))
|
||||
{
|
||||
preCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||
var preCoreType = config.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||
itemSocks = new ProfileItem()
|
||||
{
|
||||
CoreType = preCoreType,
|
||||
@@ -1872,6 +1869,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
namespace ServiceLib.Handler
|
||||
using YamlDotNet.Core.Tokens;
|
||||
|
||||
namespace ServiceLib.Handler
|
||||
{
|
||||
/// <summary>
|
||||
/// Core configuration file processing class
|
||||
/// </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;
|
||||
@@ -82,7 +86,7 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("GenerateClientCustomConfig", ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ 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)
|
||||
{
|
||||
@@ -24,16 +25,16 @@ namespace ServiceLib.Handler
|
||||
Environment.SetEnvironmentVariable("V2RAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
Environment.SetEnvironmentVariable("XRAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
|
||||
if (Utils.IsLinux() || Utils.IsOSX())
|
||||
if (Utils.IsNonWindows())
|
||||
{
|
||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
||||
foreach (var it in coreInfo)
|
||||
{
|
||||
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 +55,7 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
ShowMsg(false, ResUI.CheckServerSettings);
|
||||
UpdateFunc(false, ResUI.CheckServerSettings);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -62,13 +63,13 @@ 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(true, $"{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);
|
||||
@@ -80,15 +81,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,15 +106,13 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
if (_process != null)
|
||||
{
|
||||
await KillProcess(_process);
|
||||
_process.Dispose();
|
||||
await ProcUtils.ProcessKill(_process, true);
|
||||
_process = null;
|
||||
}
|
||||
|
||||
if (_processPre != null)
|
||||
{
|
||||
await KillProcess(_processPre);
|
||||
_processPre.Dispose();
|
||||
await ProcUtils.ProcessKill(_processPre, true);
|
||||
_processPre = null;
|
||||
}
|
||||
|
||||
@@ -117,46 +124,12 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CoreStopPid(int pid)
|
||||
{
|
||||
try
|
||||
{
|
||||
var _p = Process.GetProcessById(pid);
|
||||
await KillProcess(_p);
|
||||
}
|
||||
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);
|
||||
@@ -179,7 +152,7 @@ namespace ServiceLib.Handler
|
||||
var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType);
|
||||
if (itemSocks != null)
|
||||
{
|
||||
var preCoreType = _config.RunningCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
|
||||
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
|
||||
var fileName = Utils.GetConfigPath(Global.CorePreConfigFileName);
|
||||
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
|
||||
if (result.Success)
|
||||
@@ -196,28 +169,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);
|
||||
}
|
||||
@@ -226,7 +178,7 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
return _config.TunModeItem.EnableTun
|
||||
&& eCoreType == ECoreType.sing_box
|
||||
&& (Utils.IsLinux() || Utils.IsOSX())
|
||||
&& (Utils.IsNonWindows())
|
||||
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
|
||||
;
|
||||
}
|
||||
@@ -235,11 +187,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;
|
||||
}
|
||||
|
||||
@@ -274,12 +227,12 @@ namespace ServiceLib.Handler
|
||||
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);
|
||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
||||
|
||||
if (!startUpSuccessful)
|
||||
{
|
||||
@@ -320,40 +273,12 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
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 KillProcess(Process? proc)
|
||||
{
|
||||
if (proc is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
proc?.Kill();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
await Task.Delay(100);
|
||||
if (proc?.HasExited == false)
|
||||
{
|
||||
try
|
||||
{
|
||||
proc?.Kill();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Process
|
||||
|
||||
#region Linux
|
||||
@@ -375,7 +300,7 @@ namespace ServiceLib.Handler
|
||||
|
||||
private async Task KillProcessAsLinuxSudo()
|
||||
{
|
||||
var cmdLine = $"kill -9 {_linuxSudoPid}";
|
||||
var cmdLine = $"kill {_linuxSudoPid}";
|
||||
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
|
||||
Process proc = new()
|
||||
{
|
||||
@@ -392,26 +317,37 @@ namespace ServiceLib.Handler
|
||||
|
||||
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
||||
{
|
||||
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
|
||||
await Task.Delay(10);
|
||||
await proc.StandardInput.WriteLineAsync(pwd);
|
||||
await Task.Delay(10);
|
||||
await proc.StandardInput.WriteLineAsync(pwd);
|
||||
try
|
||||
{
|
||||
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
|
||||
await Task.Delay(10);
|
||||
await proc.StandardInput.WriteLineAsync(pwd);
|
||||
await Task.Delay(10);
|
||||
await proc.StandardInput.WriteLineAsync(pwd);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
|
||||
await proc.WaitForExitAsync(timeout.Token);
|
||||
await Task.Delay(1000);
|
||||
await Task.Delay(3000);
|
||||
}
|
||||
|
||||
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
|
||||
{
|
||||
//Shell scripts
|
||||
var shFilePath = Utils.GetBinPath(fileName);
|
||||
var shFilePath = Utils.GetBinPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
|
||||
File.Delete(shFilePath);
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("#!/bin/sh");
|
||||
if (_config.TunModeItem.LinuxSudoPwd.IsNullOrEmpty())
|
||||
if (AppHandler.Instance.IsAdministrator)
|
||||
{
|
||||
sb.AppendLine($"{cmdLine}");
|
||||
}
|
||||
else if (_config.TunModeItem.LinuxSudoPwd.IsNullOrEmpty())
|
||||
{
|
||||
sb.AppendLine($"pkexec {cmdLine}");
|
||||
}
|
||||
|
||||
@@ -29,6 +29,27 @@
|
||||
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 = [];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -99,8 +99,8 @@ namespace ServiceLib.Handler.Fmt
|
||||
{
|
||||
return null;
|
||||
}
|
||||
item.Security = userInfoParts[0];
|
||||
item.Id = Utils.UrlDecode(userInfoParts[1]);
|
||||
item.Security = userInfoParts.First();
|
||||
item.Id = Utils.UrlDecode(userInfoParts.Last());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -111,8 +111,8 @@ namespace ServiceLib.Handler.Fmt
|
||||
{
|
||||
return null;
|
||||
}
|
||||
item.Security = userInfoParts[0];
|
||||
item.Id = userInfoParts[1];
|
||||
item.Security = userInfoParts.First();
|
||||
item.Id = userInfoParts.Last();
|
||||
}
|
||||
|
||||
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
public static ProfileItem? Resolve(string str, out string msg)
|
||||
{
|
||||
msg = ResUI.ConfigurationFormatIncorrect;
|
||||
ProfileItem? item;
|
||||
|
||||
item = ResolveSocksNew(str) ?? ResolveSocks(str);
|
||||
var item = ResolveSocksNew(str) ?? ResolveSocks(str);
|
||||
if (item == null)
|
||||
{
|
||||
return null;
|
||||
@@ -25,19 +24,13 @@
|
||||
public static string? ToUri(ProfileItem? item)
|
||||
{
|
||||
if (item == null) return null;
|
||||
string url = string.Empty;
|
||||
var url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
var remark = string.Empty;
|
||||
if (Utils.IsNotEmpty(item.Remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||
}
|
||||
//url = string.Format("{0}:{1}@{2}:{3}",
|
||||
// item.security,
|
||||
// item.id,
|
||||
// item.address,
|
||||
// item.port);
|
||||
//url = Utile.Base64Encode(url);
|
||||
//new
|
||||
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
|
||||
return ToUri(EConfigType.SOCKS, item.Address, item.Port, pw, null, remark);
|
||||
@@ -51,7 +44,7 @@
|
||||
};
|
||||
result = result[Global.ProtocolShares[EConfigType.SOCKS].Length..];
|
||||
//remark
|
||||
int indexRemark = result.IndexOf("#");
|
||||
var indexRemark = result.IndexOf("#");
|
||||
if (indexRemark > 0)
|
||||
{
|
||||
try
|
||||
@@ -62,7 +55,7 @@
|
||||
result = result[..indexRemark];
|
||||
}
|
||||
//part decode
|
||||
int indexS = result.IndexOf("@");
|
||||
var indexS = result.IndexOf("@");
|
||||
if (indexS > 0)
|
||||
{
|
||||
}
|
||||
@@ -71,21 +64,20 @@
|
||||
result = Utils.Base64Decode(result);
|
||||
}
|
||||
|
||||
string[] arr1 = result.Split('@');
|
||||
var arr1 = result.Split('@');
|
||||
if (arr1.Length != 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string[] arr21 = arr1[0].Split(':');
|
||||
//string[] arr22 = arr1[1].Split(':');
|
||||
int indexPort = arr1[1].LastIndexOf(":");
|
||||
var arr21 = arr1.First().Split(':');
|
||||
var indexPort = arr1.Last().LastIndexOf(":");
|
||||
if (arr21.Length != 2 || indexPort < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
item.Address = arr1[1][..indexPort];
|
||||
item.Port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
|
||||
item.Security = arr21[0];
|
||||
item.Security = arr21.First();
|
||||
item.Id = arr21[1];
|
||||
|
||||
return item;
|
||||
@@ -106,10 +98,10 @@
|
||||
// parse base64 UserInfo
|
||||
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
|
||||
var userInfo = Utils.Base64Decode(rawUserInfo);
|
||||
var userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
||||
var userInfoParts = userInfo.Split([':'], 2);
|
||||
if (userInfoParts.Length == 2)
|
||||
{
|
||||
item.Security = userInfoParts[0];
|
||||
item.Security = userInfoParts.First();
|
||||
item.Id = userInfoParts[1];
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
|
||||
if (userInfoParts.Length == 2)
|
||||
{
|
||||
item.Id = userInfoParts[0];
|
||||
item.Security = userInfoParts[1];
|
||||
item.Id = userInfoParts.First();
|
||||
item.Security = userInfoParts.Last();
|
||||
}
|
||||
|
||||
var query = Utils.ParseQueryString(url.Query);
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
@@ -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,7 +12,7 @@
|
||||
|
||||
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)
|
||||
@@ -39,7 +39,7 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
{
|
||||
public class ProxySettingLinux
|
||||
{
|
||||
public static async Task SetProxy(string host, int port)
|
||||
public static async Task SetProxy(string host, int port, string exceptions)
|
||||
{
|
||||
var lstCmd = GetSetCmds(host, port);
|
||||
var lstCmd = GetSetCmds(host, port, exceptions);
|
||||
|
||||
await ExecCmd(lstCmd);
|
||||
}
|
||||
@@ -29,25 +29,39 @@
|
||||
}
|
||||
}
|
||||
|
||||
private static List<CmdItem> GetSetCmds(string host, int port)
|
||||
private static List<CmdItem> GetSetCmds(string host, int port, string exceptions)
|
||||
{
|
||||
var isKde = IsKde(out var configDir);
|
||||
List<string> lstType = ["", "http", "https", "socks", "ftp"];
|
||||
List<CmdItem> lstCmd = [];
|
||||
|
||||
//GNOME
|
||||
foreach (var type in lstType)
|
||||
{
|
||||
lstCmd.AddRange(GetSetCmd4Gnome(type, host, port));
|
||||
}
|
||||
if (exceptions.IsNotEmpty())
|
||||
{
|
||||
lstCmd.AddRange(GetSetCmd4Gnome("exceptions", exceptions, 0));
|
||||
}
|
||||
|
||||
if (isKde)
|
||||
{
|
||||
foreach (var type in lstType)
|
||||
{
|
||||
lstCmd.AddRange(GetSetCmd4Kde(type, host, port, configDir));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var type in lstType)
|
||||
if (exceptions.IsNotEmpty())
|
||||
{
|
||||
lstCmd.AddRange(GetSetCmd4Gnome(type, host, port));
|
||||
lstCmd.AddRange(GetSetCmd4Kde("exceptions", exceptions, 0, configDir));
|
||||
}
|
||||
|
||||
// Notify system to reload
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "dbus-send",
|
||||
Arguments = ["--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''"]
|
||||
});
|
||||
}
|
||||
return lstCmd;
|
||||
}
|
||||
@@ -57,44 +71,58 @@
|
||||
var isKde = IsKde(out var configDir);
|
||||
List<CmdItem> lstCmd = [];
|
||||
|
||||
//GNOME
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "gsettings",
|
||||
Arguments = ["set", "org.gnome.system.proxy", "mode", "none"]
|
||||
});
|
||||
|
||||
if (isKde)
|
||||
{
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "kwriteconfig5",
|
||||
Cmd = GetKdeVersion(),
|
||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0"]
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Notify system to reload
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "gsettings",
|
||||
Arguments = ["set", "org.gnome.system.proxy", "mode", "none"]
|
||||
Cmd = "dbus-send",
|
||||
Arguments = ["--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''"]
|
||||
});
|
||||
}
|
||||
|
||||
return lstCmd;
|
||||
}
|
||||
|
||||
private static List<CmdItem> GetSetCmd4Kde(string type, string host, int port, string configDir)
|
||||
{
|
||||
List<CmdItem> lstCmd = [];
|
||||
var cmd = GetKdeVersion();
|
||||
|
||||
if (type.IsNullOrEmpty())
|
||||
{
|
||||
lstCmd.Add(new()
|
||||
{
|
||||
Cmd = "kwriteconfig5",
|
||||
Cmd = cmd,
|
||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1"]
|
||||
});
|
||||
}
|
||||
else if (type == "exceptions")
|
||||
{
|
||||
lstCmd.Add(new()
|
||||
{
|
||||
Cmd = cmd,
|
||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "NoProxyFor", host]
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var type2 = type.Equals("https") ? "http" : type;
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "kwriteconfig5",
|
||||
Cmd = cmd,
|
||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", $"{type}Proxy", $"{type2}://{host}:{port}"]
|
||||
});
|
||||
}
|
||||
@@ -114,6 +142,14 @@
|
||||
Arguments = ["set", "org.gnome.system.proxy", "mode", "manual"]
|
||||
});
|
||||
}
|
||||
else if (type == "exceptions")
|
||||
{
|
||||
lstCmd.Add(new()
|
||||
{
|
||||
Cmd = "gsettings",
|
||||
Arguments = ["set", $"org.gnome.system.proxy", "ignore-hosts", JsonUtils.Serialize(host.Split(','), false)]
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
lstCmd.Add(new()
|
||||
@@ -136,7 +172,11 @@
|
||||
{
|
||||
configDir = "/home";
|
||||
var desktop = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP");
|
||||
var isKde = string.Equals(desktop, "KDE", StringComparison.OrdinalIgnoreCase);
|
||||
var desktop2 = Environment.GetEnvironmentVariable("XDG_SESSION_DESKTOP");
|
||||
var isKde = string.Equals(desktop, "KDE", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(desktop, "plasma", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(desktop2, "KDE", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(desktop2, "plasma", StringComparison.OrdinalIgnoreCase);
|
||||
if (isKde)
|
||||
{
|
||||
var homeDir = Environment.GetEnvironmentVariable("HOME");
|
||||
@@ -148,5 +188,15 @@
|
||||
|
||||
return isKde;
|
||||
}
|
||||
|
||||
private static string GetKdeVersion()
|
||||
{
|
||||
var ver = Environment.GetEnvironmentVariable("KDE_SESSION_VERSION") ?? "0";
|
||||
return ver switch
|
||||
{
|
||||
"6" => "kwriteconfig6",
|
||||
_ => "kwriteconfig5"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,29 +2,27 @@
|
||||
{
|
||||
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
|
||||
/// </summary>
|
||||
private static readonly List<string> LstTypes = ["setwebproxy", "setsecurewebproxy", "setsocksfirewallproxy"];
|
||||
|
||||
public static async Task SetProxy(string host, int port)
|
||||
public static async Task SetProxy(string host, int port, string exceptions)
|
||||
{
|
||||
var lstCmd = GetSetCmds(host, port);
|
||||
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,17 +40,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
private static List<CmdItem> GetSetCmds(string host, int port)
|
||||
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)
|
||||
{
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "networksetup",
|
||||
Arguments = [$"-{type}", interf, host, (type.Contains("socks") ? (port - 1) : port).ToString()]
|
||||
Arguments = [$"-{type}", interf, host, port.ToString()]
|
||||
});
|
||||
}
|
||||
if (exceptions.IsNotEmpty())
|
||||
{
|
||||
List<string> args = [$"-setproxybypassdomains", interf];
|
||||
args.AddRange(exceptions.Split(','));
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "networksetup",
|
||||
Arguments = args
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -60,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)
|
||||
{
|
||||
@@ -77,5 +85,16 @@
|
||||
|
||||
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);
|
||||
return lst.Length > 0 ? LstInterface.Intersect(lst).ToList() : LstInterface;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,7 @@
|
||||
{
|
||||
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;
|
||||
@@ -13,8 +14,8 @@
|
||||
|
||||
try
|
||||
{
|
||||
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.http);
|
||||
var portSocks = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||
var exceptions = config.SystemProxyItem.SystemProxyExceptions;
|
||||
if (port <= 0)
|
||||
{
|
||||
return false;
|
||||
@@ -23,16 +24,16 @@
|
||||
{
|
||||
case ESysProxyType.ForcedChange when Utils.IsWindows():
|
||||
{
|
||||
GetWindowsProxyString(config, port, portSocks, out var strProxy, out var strExceptions);
|
||||
GetWindowsProxyString(config, port, out var strProxy, out var strExceptions);
|
||||
ProxySettingWindows.SetProxy(strProxy, strExceptions, 2);
|
||||
break;
|
||||
}
|
||||
case ESysProxyType.ForcedChange when Utils.IsLinux():
|
||||
await ProxySettingLinux.SetProxy(Global.Loopback, port);
|
||||
await ProxySettingLinux.SetProxy(Global.Loopback, port, exceptions);
|
||||
break;
|
||||
|
||||
case ESysProxyType.ForcedChange when Utils.IsOSX():
|
||||
await ProxySettingOSX.SetProxy(Global.Loopback, port);
|
||||
await ProxySettingOSX.SetProxy(Global.Loopback, port, exceptions);
|
||||
break;
|
||||
|
||||
case ESysProxyType.ForcedClear when Utils.IsWindows():
|
||||
@@ -59,17 +60,17 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void GetWindowsProxyString(Config config, int port, int portSocks, out string strProxy, out string strExceptions)
|
||||
private static void GetWindowsProxyString(Config config, int port, out string strProxy, out string strExceptions)
|
||||
{
|
||||
strExceptions = "";
|
||||
strExceptions = config.SystemProxyItem.SystemProxyExceptions;
|
||||
if (config.SystemProxyItem.NotProxyLocalAddress)
|
||||
{
|
||||
strExceptions = $"<local>;{config.ConstItem.DefIEProxyExceptions};{config.SystemProxyItem.SystemProxyExceptions}";
|
||||
strExceptions = $"<local>;{strExceptions}";
|
||||
}
|
||||
|
||||
strProxy = string.Empty;
|
||||
@@ -82,7 +83,7 @@
|
||||
strProxy = config.SystemProxyItem.SystemProxyAdvancedProtocol
|
||||
.Replace("{ip}", Global.Loopback)
|
||||
.Replace("{http_port}", port.ToString())
|
||||
.Replace("{socks_port}", portSocks.ToString());
|
||||
.Replace("{socks_port}", port.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@ 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 +82,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()
|
||||
|
||||
@@ -24,21 +24,16 @@
|
||||
public class InItem
|
||||
{
|
||||
public int LocalPort { get; set; }
|
||||
|
||||
public string Protocol { get; set; }
|
||||
|
||||
public bool UdpEnabled { get; set; }
|
||||
|
||||
public bool SniffingEnabled { get; set; } = true;
|
||||
public List<string>? DestOverride { get; set; } = ["http", "tls"];
|
||||
public bool RouteOnly { get; set; }
|
||||
public bool AllowLANConn { get; set; }
|
||||
|
||||
public bool NewPort4LAN { get; set; }
|
||||
|
||||
public string User { get; set; }
|
||||
|
||||
public string Pass { get; set; }
|
||||
public bool SecondLocalPortEnabled { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
@@ -171,6 +166,7 @@
|
||||
public int SpeedTestTimeout { get; set; }
|
||||
public string SpeedTestUrl { get; set; }
|
||||
public string SpeedPingTestUrl { get; set; }
|
||||
public int SpeedTestPageSize { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
@@ -222,7 +218,6 @@
|
||||
public int ProxiesSorting { get; set; }
|
||||
public bool ProxiesAutoRefresh { get; set; }
|
||||
public int ProxiesAutoDelayTestInterval { get; set; } = 10;
|
||||
public int ConnectionsSorting { get; set; }
|
||||
public bool ConnectionsAutoRefresh { get; set; }
|
||||
public int ConnectionsRefreshInterval { get; set; } = 2;
|
||||
}
|
||||
|
||||
@@ -324,7 +324,8 @@ namespace ServiceLib.Models
|
||||
|
||||
public class WsSettings4Ray
|
||||
{
|
||||
public string path { get; set; }
|
||||
public string? path { get; set; }
|
||||
public string? host { get; set; }
|
||||
|
||||
public Headers4Ray headers { get; set; }
|
||||
}
|
||||
@@ -349,21 +350,9 @@ namespace ServiceLib.Models
|
||||
public string? path { get; set; }
|
||||
public string? host { get; set; }
|
||||
public string? mode { get; set; }
|
||||
public string? scMaxEachPostBytes { get; set; }
|
||||
public string? scMaxConcurrentPosts { get; set; }
|
||||
public string? scMinPostsIntervalMs { get; set; }
|
||||
public Xmux4Ray? xmux { get; set; }
|
||||
public object? extra { get; set; }
|
||||
}
|
||||
|
||||
public class Xmux4Ray
|
||||
{
|
||||
public int? maxConcurrency { get; set; }
|
||||
public int? maxConnections { get; set; }
|
||||
public int? cMaxReuseTimes { get; set; }
|
||||
public int? cMaxLifetimeMs { get; set; }
|
||||
}
|
||||
|
||||
public class HttpSettings4Ray
|
||||
{
|
||||
public string? path { get; set; }
|
||||
|
||||
60
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
60
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -1248,6 +1248,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Iran 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuRegionalPresetsIran {
|
||||
get {
|
||||
return ResourceManager.GetString("menuRegionalPresetsIran", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Russia 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2599,6 +2608,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 socks: local port, socks2: second local port, socks3: LAN port 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbRoutingInboundTagTips {
|
||||
get {
|
||||
return ResourceManager.GetString("TbRoutingInboundTagTips", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Domain 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2914,6 +2932,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Sniffing type 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsDestOverride {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsDestOverride", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Outbound DNS address 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -3058,6 +3085,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Exception. Do not use proxy server for addresses,with a comma (,) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsExceptionTip2 {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsExceptionTip2", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Follow System Theme 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -3140,7 +3176,7 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Linux system sudo password 的本地化字符串。
|
||||
/// 查找类似 System sudo password 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsLinuxSudoPassword {
|
||||
get {
|
||||
@@ -3292,6 +3328,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable second mixed port 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsSecondLocalPortEnabled {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsSecondLocalPortEnabled", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Set Win10 UWP Loopback 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -3311,7 +3356,7 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 SOCKS Port 的本地化字符串。
|
||||
/// 查找类似 Mixed Port 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsSocksPort {
|
||||
get {
|
||||
@@ -3320,7 +3365,7 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6; 的本地化字符串。
|
||||
/// 查找类似 Pac port = +3; Xray API port = +4; mihomo API port = +5; 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsSocksPortTip {
|
||||
get {
|
||||
@@ -3337,6 +3382,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Number per time for auto batch during speedtest(max 1000) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsSpeedTestPageSize {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsSpeedTestPageSize", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 SpeedTest Single Timeout Value 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||
<value>Batch export share URL to clipboard successfully</value>
|
||||
<value>ارسال دسته ای آدرس اینترنتی اشتراک گذاری به کلیپ بورد با موفقیت.</value>
|
||||
</data>
|
||||
<data name="CheckServerSettings" xml:space="preserve">
|
||||
<value>لطفا ابتدا تنظیمات سرور را بررسی کنید</value>
|
||||
@@ -136,7 +136,7 @@
|
||||
<value>دانلود</value>
|
||||
</data>
|
||||
<data name="DownloadYesNo" xml:space="preserve">
|
||||
<value>Whether to download? {0}</value>
|
||||
<value>آیا برای دانلود؟ {0}</value>
|
||||
</data>
|
||||
<data name="FailedConversionConfiguration" xml:space="preserve">
|
||||
<value>تبدیل فایل پیکربندی انجام نشد</value>
|
||||
@@ -226,7 +226,7 @@
|
||||
<value>هیچ اشتراک معتبری تنظیم نشده است</value>
|
||||
</data>
|
||||
<data name="MsgParsingSuccessfully" xml:space="preserve">
|
||||
<value>Resolve {0} successfully</value>
|
||||
<value>حل {0} با موفقیت</value>
|
||||
</data>
|
||||
<data name="MsgStartGettingSubscriptions" xml:space="preserve">
|
||||
<value>شروع به دریافت اشتراک شد</value>
|
||||
@@ -253,19 +253,19 @@
|
||||
<value>هسته با موفقیت بروزرسانی شد! راه اندازی مجدد سرویس...</value>
|
||||
</data>
|
||||
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
||||
<value>Non-VMess or ss protocol</value>
|
||||
<value>پروتکل غیر VMess یا ss</value>
|
||||
</data>
|
||||
<data name="NotFoundCore" xml:space="preserve">
|
||||
<value>The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2}</value>
|
||||
<value>فایل Core (نام فایل: {1}) در زیر پوشه ({0}) یافت نشد، لطفاً آن را دانلود کرده و در پوشه قرار دهید، آدرس دانلود: {2}</value>
|
||||
</data>
|
||||
<data name="NoValidQRcodeFound" xml:space="preserve">
|
||||
<value>Scan completed, no valid QR code found</value>
|
||||
<value>اسکن کامل شد، QRcode معتبری یافت نشد</value>
|
||||
</data>
|
||||
<data name="OperationFailed" xml:space="preserve">
|
||||
<value> عملیات انجام نشد، لطفا بررسی کنید و دوباره امتحان کنید</value>
|
||||
</data>
|
||||
<data name="PleaseFillRemarks" xml:space="preserve">
|
||||
<value>Please Fill Remarks</value>
|
||||
<value>لطفا ملاحظات را پر کنید</value>
|
||||
</data>
|
||||
<data name="PleaseSelectEncryption" xml:space="preserve">
|
||||
<value>لطفاً روش رمزگذاری را انتخاب کنید</value>
|
||||
@@ -277,16 +277,16 @@
|
||||
<value>لطفا ابتدا سرور را انتخاب کنید</value>
|
||||
</data>
|
||||
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
||||
<value>Servers deduplication completed. Old: {0}, New: {1}.</value>
|
||||
<value>حذف مجدد سرورها تکمیل شد. قدیمی: {0}، جدید: {1}.</value>
|
||||
</data>
|
||||
<data name="RemoveServer" xml:space="preserve">
|
||||
<value>آیا مطمئن هستید که سرور را حذف می کنید؟</value>
|
||||
</data>
|
||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||
<value>The client configuration file is saved at: {0}</value>
|
||||
<value>فایل پیکربندی کلاینت در این آدرس ذخیره می شود: {0}</value>
|
||||
</data>
|
||||
<data name="StartService" xml:space="preserve">
|
||||
<value>Start service ({0})...</value>
|
||||
<value>شروع سرویس ({0})...</value>
|
||||
</data>
|
||||
<data name="SuccessfulConfiguration" xml:space="preserve">
|
||||
<value>پیکربندی با موفقیت انجام شد
|
||||
@@ -317,19 +317,19 @@
|
||||
<value>{0},یکی از مورد نیاز.</value>
|
||||
</data>
|
||||
<data name="LvRemarks" xml:space="preserve">
|
||||
<value>Remarks</value>
|
||||
<value>ملاحظات</value>
|
||||
</data>
|
||||
<data name="LvUrl" xml:space="preserve">
|
||||
<value>Url(Optional)</value>
|
||||
<value>آدرس اینترنتی (اختیاری)</value>
|
||||
</data>
|
||||
<data name="LvCount" xml:space="preserve">
|
||||
<value>Count</value>
|
||||
<value>شمارش</value>
|
||||
</data>
|
||||
<data name="MsgNeedUrl" xml:space="preserve">
|
||||
<value>Please fill in the address (Url)</value>
|
||||
<value>لطفا آدرس (آدرس اینترنتی) را وارد کنید</value>
|
||||
</data>
|
||||
<data name="AddBatchRoutingRulesYesNo" xml:space="preserve">
|
||||
<value>Do you want to append rules? Choose yes to append, choose otherwise to replace</value>
|
||||
<value>آیا می خواهید قوانین را اضافه کنید؟ برای ضمیمه بله را انتخاب کنید، در غیر این صورت جایگزین کنید</value>
|
||||
</data>
|
||||
<data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve">
|
||||
<value>دانلود GeoFile: {0} با موفقیت</value>
|
||||
@@ -386,10 +386,10 @@
|
||||
<value>*Kcp seed</value>
|
||||
</data>
|
||||
<data name="RegisterGlobalHotkeyFailed" xml:space="preserve">
|
||||
<value>Global hotkey {0} registered failed, reason {1}</value>
|
||||
<value>کلید میانبر جهانی {0} ثبت نشد، دلیل کلید میانبر جهانی {0} ثبت ناموفق بود، دلیل {1}{1}</value>
|
||||
</data>
|
||||
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
|
||||
<value>Global hotkey {0} registered successfully</value>
|
||||
<value>کلید میانبر جهانی {0} با موفقیت ثبت شد</value>
|
||||
</data>
|
||||
<data name="UngroupedServers" xml:space="preserve">
|
||||
<value>گروه بندی نشده</value>
|
||||
@@ -398,7 +398,7 @@
|
||||
<value>همه سرورها</value>
|
||||
</data>
|
||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||
<value>Please browse to import server configuration</value>
|
||||
<value>لطفاً برای وارد کردن پیکربندی سرور مرور کنید</value>
|
||||
</data>
|
||||
<data name="Speedtesting" xml:space="preserve">
|
||||
<value>درحال تست کردن...</value>
|
||||
@@ -593,7 +593,7 @@
|
||||
<value>آدرس</value>
|
||||
</data>
|
||||
<data name="TbAllowInsecure" xml:space="preserve">
|
||||
<value>اجازه ناامن</value>
|
||||
<value>اعطای مجوز ناامن</value>
|
||||
</data>
|
||||
<data name="TbAlpn" xml:space="preserve">
|
||||
<value>Alpn</value>
|
||||
@@ -602,10 +602,10 @@
|
||||
<value>AlterId</value>
|
||||
</data>
|
||||
<data name="TbFingerprint" xml:space="preserve">
|
||||
<value>Fingerprint</value>
|
||||
<value>اثرانگشت</value>
|
||||
</data>
|
||||
<data name="TbHeaderType" xml:space="preserve">
|
||||
<value>Camouflage type</value>
|
||||
<value>نوع Camouflage</value>
|
||||
</data>
|
||||
<data name="TbId" xml:space="preserve">
|
||||
<value>UUID(id)</value>
|
||||
@@ -620,13 +620,13 @@
|
||||
<value>پورت</value>
|
||||
</data>
|
||||
<data name="TbRemarks" xml:space="preserve">
|
||||
<value>Alias (remarks)</value>
|
||||
<value>نام مستعار (ملاحظات)</value>
|
||||
</data>
|
||||
<data name="TbRequestHost" xml:space="preserve">
|
||||
<value>Camouflage domain(host)</value>
|
||||
</data>
|
||||
<data name="TbSecurity" xml:space="preserve">
|
||||
<value>Encryption method (security)</value>
|
||||
<value>روش رمزگذاری (امنیتی)</value>
|
||||
</data>
|
||||
<data name="TbSNI" xml:space="preserve">
|
||||
<value>SNI</value>
|
||||
@@ -635,7 +635,7 @@
|
||||
<value>TLS</value>
|
||||
</data>
|
||||
<data name="TipNetwork" xml:space="preserve">
|
||||
<value>*Default value tcp</value>
|
||||
<value>*مقدار پیش فرض tcp</value>
|
||||
</data>
|
||||
<data name="TbCoreType" xml:space="preserve">
|
||||
<value>نوع هسته</value>
|
||||
@@ -644,7 +644,7 @@
|
||||
<value>جریان</value>
|
||||
</data>
|
||||
<data name="TbGUID" xml:space="preserve">
|
||||
<value>Generate</value>
|
||||
<value>ساختن</value>
|
||||
</data>
|
||||
<data name="TbId3" xml:space="preserve">
|
||||
<value>رمزعبور</value>
|
||||
@@ -668,10 +668,10 @@
|
||||
<value>txtPreSocksPort</value>
|
||||
</data>
|
||||
<data name="TipPreSocksPort" xml:space="preserve">
|
||||
<value>* After setting this value, an socks service will be started using Xray/sing-box(Tun) to provide functions such as speed display</value>
|
||||
<value>* پس از تنظیم این مقدار، یک سرویس جوراب با استفاده از Xray/sing-box (Tun) برای ارائه عملکردهایی مانند نمایش سرعت شروع می شود.</value>
|
||||
</data>
|
||||
<data name="TbBrowse" xml:space="preserve">
|
||||
<value>Browse</value>
|
||||
<value>مرور کردن</value>
|
||||
</data>
|
||||
<data name="TbEdit" xml:space="preserve">
|
||||
<value>ویرایش</value>
|
||||
@@ -683,7 +683,7 @@
|
||||
<value>اتصالات از LAN را مجاز کنید</value>
|
||||
</data>
|
||||
<data name="TbSettingsAutoHideStartup" xml:space="preserve">
|
||||
<value>Auto hide startup</value>
|
||||
<value>راه اندازی مخفی کردن خودکار</value>
|
||||
</data>
|
||||
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
|
||||
<value>فاصله به روز رسانی خودکار و Geo (ساعت)</value>
|
||||
@@ -692,7 +692,7 @@
|
||||
<value>هسته: تنظیمات اولیه</value>
|
||||
</data>
|
||||
<data name="TbSettingsCoreDns" xml:space="preserve">
|
||||
<value>V2ray DNS settings</value>
|
||||
<value>تنظیمات V2ray DNS</value>
|
||||
</data>
|
||||
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
||||
<value>هسته: تنظیمات KCP</value>
|
||||
@@ -701,7 +701,7 @@
|
||||
<value>تنظیمات CoreType</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefAllowInsecure" xml:space="preserve">
|
||||
<value>اجازه ناامن</value>
|
||||
<value>اعطای مجوز ناامن</value>
|
||||
</data>
|
||||
<data name="TbSettingsDomainStrategy4Freedom" xml:space="preserve">
|
||||
<value>Outbound Freedom domainStrategy</value>
|
||||
@@ -716,7 +716,7 @@
|
||||
<value>استثنا</value>
|
||||
</data>
|
||||
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
||||
<value>Exception. Do not use proxy server for addresses beginning with,Use semicolon (;)</value>
|
||||
<value>استثنا: از سرور پروکسی برای آدرس هایی که با شروع می شوند استفاده نکنید، از نقطه ویرگول (;) استفاده کنید.</value>
|
||||
</data>
|
||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
||||
<value>پورت Http</value>
|
||||
@@ -725,7 +725,7 @@
|
||||
<value>هنگام بهروزرسانی هسته، فایلهای Geo را نادیده بگیرید</value>
|
||||
</data>
|
||||
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
|
||||
<value>Keep older when deduplication</value>
|
||||
<value>هنگام کپی برداری، نگه داری قدیمی تر ها</value>
|
||||
</data>
|
||||
<data name="TbSettingsLogEnabled" xml:space="preserve">
|
||||
<value>ثبت گزارش های محلی</value>
|
||||
@@ -734,25 +734,25 @@
|
||||
<value>سطح ثبت رویداد</value>
|
||||
</data>
|
||||
<data name="TbSettingsMuxEnabled" xml:space="preserve">
|
||||
<value>Turn on Mux Multiplexing</value>
|
||||
<value>فعال کردن Mux Multiplexing</value>
|
||||
</data>
|
||||
<data name="TbSettingsN" xml:space="preserve">
|
||||
<value>تنظیمات v2rayN</value>
|
||||
</data>
|
||||
<data name="TbSettingsPass" xml:space="preserve">
|
||||
<value>Auth pass</value>
|
||||
<value>مجوز احراز هویت</value>
|
||||
</data>
|
||||
<data name="TbSettingsRemoteDNS" xml:space="preserve">
|
||||
<value>سفارشی DNS (multiple, separated by commas (,))</value>
|
||||
</data>
|
||||
<data name="TbSettingsSetUWP" xml:space="preserve">
|
||||
<value>Set Win10 UWP Loopback</value>
|
||||
<value>تنظیم کردن Win10 UWP Loopback</value>
|
||||
</data>
|
||||
<data name="TbSettingsSniffingEnabled" xml:space="preserve">
|
||||
<value>Turn on Sniffing</value>
|
||||
<value>فعال کردن Sniffing</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPort" xml:space="preserve">
|
||||
<value>ساکس Port</value>
|
||||
<value>پورت Mixed</value>
|
||||
</data>
|
||||
<data name="TbSettingsStartBoot" xml:space="preserve">
|
||||
<value>درهنگام راه ائدازی شروع شود</value>
|
||||
@@ -761,22 +761,22 @@
|
||||
<value>فعال کردن آمار (نیاز به راه اندازی مجدد)</value>
|
||||
</data>
|
||||
<data name="TbSettingsSubConvert" xml:space="preserve">
|
||||
<value>Subscription conversion Url</value>
|
||||
<value>آدرس اینترنتی تبدیل اشتراک</value>
|
||||
</data>
|
||||
<data name="TbSettingsSystemproxy" xml:space="preserve">
|
||||
<value>تنظیمات پراکسی سیستم</value>
|
||||
</data>
|
||||
<data name="TbSettingsTLS13" xml:space="preserve">
|
||||
<value>Enable Security Protocol TLS v1.3 (subscription/update)</value>
|
||||
<value>فعال کردن پروتکل امنیتی TLS نسخه 1.3 (اشتراک/بهروزرسانی)</value>
|
||||
</data>
|
||||
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
|
||||
<value>Tray right-click menu servers display limit</value>
|
||||
<value>محدودیت نمایش سرورهای منوی سینی کلیک راست</value>
|
||||
</data>
|
||||
<data name="TbSettingsUdpEnabled" xml:space="preserve">
|
||||
<value>UDP را فعال شود</value>
|
||||
<value>فعال سازی UDP</value>
|
||||
</data>
|
||||
<data name="TbSettingsUser" xml:space="preserve">
|
||||
<value>Auth user</value>
|
||||
<value>تایید کاربر</value>
|
||||
</data>
|
||||
<data name="TbClearSystemProxy" xml:space="preserve">
|
||||
<value>پاک کردن پروکسی سیستم</value>
|
||||
@@ -821,16 +821,16 @@
|
||||
<value>پایین (D)</value>
|
||||
</data>
|
||||
<data name="menuMoveTop" xml:space="preserve">
|
||||
<value>Move to top (T)</value>
|
||||
<value>حرکت به بالا (T)</value>
|
||||
</data>
|
||||
<data name="menuMoveUp" xml:space="preserve">
|
||||
<value>Up (U)</value>
|
||||
<value>بالا (U)</value>
|
||||
</data>
|
||||
<data name="MsgFilterTitle" xml:space="preserve">
|
||||
<value>Filter, support regular</value>
|
||||
<value>فیلتر، پشتیبانی منظم</value>
|
||||
</data>
|
||||
<data name="menuWebsiteItem" xml:space="preserve">
|
||||
<value>{0} Website</value>
|
||||
<value>{0} وب سایت</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvanced" xml:space="preserve">
|
||||
<value>عملکرد پیشرفته</value>
|
||||
@@ -845,7 +845,7 @@
|
||||
<value>حذف انتخاب شده</value>
|
||||
</data>
|
||||
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
|
||||
<value>Set as active rule</value>
|
||||
<value>تنظیم کردن به عنوان قانون فعال</value>
|
||||
</data>
|
||||
<data name="TbdomainMatcher" xml:space="preserve">
|
||||
<value>تطبیق دامنه</value>
|
||||
@@ -857,19 +857,19 @@
|
||||
<value>فعال کردن عملکرد پیشرفته</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
||||
<value>3.Block Domain or IP</value>
|
||||
<value>3. مسدود کردن دامنه یا آیپی</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabDirect" xml:space="preserve">
|
||||
<value>2.Direct Domain or IP</value>
|
||||
<value>2. دایرکت کردن دامنه یا IP</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabProxy" xml:space="preserve">
|
||||
<value>1.Proxy Domain or IP</value>
|
||||
<value>1. پروکسی کردن دامنه یا IP</value>
|
||||
</data>
|
||||
<data name="TbRoutingTabRuleList" xml:space="preserve">
|
||||
<value>لیست مجموعه قوانین از پیش تعریف شده</value>
|
||||
</data>
|
||||
<data name="TbRoutingTips" xml:space="preserve">
|
||||
<value>*Set the rules, separated by commas (,); The comma in the regular is replaced by <COMMA></value>
|
||||
<value>*قوانین را تنظیم کنید که با کاما از هم جدا شده اند (,); کاما در حالت عادی با <COMMA></value>
|
||||
</data>
|
||||
<data name="menuImportRulesFromClipboard" xml:space="preserve">
|
||||
<value>وارد کردن قوانین از کلیپ بورد</value>
|
||||
@@ -878,7 +878,7 @@
|
||||
<value>وارد کردن قوانین از فایل</value>
|
||||
</data>
|
||||
<data name="menuImportRulesFromUrl" xml:space="preserve">
|
||||
<value>وارد کردن قوانین از Sub Url</value>
|
||||
<value>وارد کردن قوانین از آدرس اینترنتی Sub</value>
|
||||
</data>
|
||||
<data name="menuRoutingRuleSetting" xml:space="preserve">
|
||||
<value>تنظیم قانون</value>
|
||||
@@ -902,7 +902,7 @@
|
||||
<value>دامنه و آی پی در هنگام ذخیره به طور خودکار مرتب می شوند</value>
|
||||
</data>
|
||||
<data name="TbRuleobjectDoc" xml:space="preserve">
|
||||
<value>Ruleobject Doc</value>
|
||||
<value>مستندات شی قانون</value>
|
||||
</data>
|
||||
<data name="TbDnsObjectDoc" xml:space="preserve">
|
||||
<value>پشتیبانی از DnsObject</value>
|
||||
@@ -920,16 +920,16 @@
|
||||
<value>فقط مسیر</value>
|
||||
</data>
|
||||
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||
<value>يەرلىك (Intranet) ئادرېسلارغا ۋاكالەتچى مۇلازىمېتىر ئىشلەتمەڭ</value>
|
||||
<value>از سرورهای پروکسی برای آدرس های محلی (اینترانت) استفاده نکنید</value>
|
||||
</data>
|
||||
<data name="menuMixedTestServer" xml:space="preserve">
|
||||
<value>One-click test Latency and speed (Ctrl+E)</value>
|
||||
<value>تاخیر و سرعت تست با یک کلیک (Ctrl+E)</value>
|
||||
</data>
|
||||
<data name="LvTestDelay" xml:space="preserve">
|
||||
<value>تاخیر (میلیثانیه)</value>
|
||||
</data>
|
||||
<data name="LvTestSpeed" xml:space="preserve">
|
||||
<value>Speed(M/s)</value>
|
||||
<value>سرعت (M/s)</value>
|
||||
</data>
|
||||
<data name="FailedToRunCore" xml:space="preserve">
|
||||
<value>Core اجرا نشد، لطفاً گزارش را ببینید</value>
|
||||
@@ -944,7 +944,7 @@
|
||||
<value>پیکربندی قدیمی guiNConfig را وارد شود</value>
|
||||
</data>
|
||||
<data name="TbEnableTunAs" xml:space="preserve">
|
||||
<value>Tun را فعال شود</value>
|
||||
<value>فعال سازی Tun</value>
|
||||
</data>
|
||||
<data name="TbSettingsNewPort4LAN" xml:space="preserve">
|
||||
<value>پورت جدید برای LAN</value>
|
||||
@@ -956,10 +956,10 @@
|
||||
<value>User-Agent</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefUserAgentTips" xml:space="preserve">
|
||||
<value>This parameter is valid only for tcp/http and ws</value>
|
||||
<value>این پارامتر فقط برای tcp/http و ws معتبر است</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableHWA" xml:space="preserve">
|
||||
<value>فعالسازی شتابدهنده سختافزاری (نیاز به راهاندازی مجدد)</value>
|
||||
<value>فعال سازی شتاب دهنده سختافزاری (نیاز به راهاندازی مجدد)</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
||||
<value>فعال کردن کش فایل مجموعه قوانین برای sing-box</value>
|
||||
@@ -968,7 +968,7 @@
|
||||
<value>مرتب سازی</value>
|
||||
</data>
|
||||
<data name="TbSortingDefault" xml:space="preserve">
|
||||
<value>Default</value>
|
||||
<value>پیش فرض</value>
|
||||
</data>
|
||||
<data name="TbSortingDelay" xml:space="preserve">
|
||||
<value>تاخیر</value>
|
||||
@@ -1007,10 +1007,10 @@
|
||||
<value>نوع قانون</value>
|
||||
</data>
|
||||
<data name="menuModeDirect" xml:space="preserve">
|
||||
<value>Direct</value>
|
||||
<value>مستقیم</value>
|
||||
</data>
|
||||
<data name="menuModeGlobal" xml:space="preserve">
|
||||
<value>Global</value>
|
||||
<value>جهانی</value>
|
||||
</data>
|
||||
<data name="menuModeNothing" xml:space="preserve">
|
||||
<value>تغییر نده</value>
|
||||
@@ -1019,193 +1019,196 @@
|
||||
<value>قانون</value>
|
||||
</data>
|
||||
<data name="menuProxiesDelaytest" xml:space="preserve">
|
||||
<value>Latency Test</value>
|
||||
<value>تست تأخیر</value>
|
||||
</data>
|
||||
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
||||
<value>Part Node Latency Test</value>
|
||||
<value>تست تاخیر قسمت گره (نقطه اتصال)</value>
|
||||
</data>
|
||||
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||
<value>Select active node (Enter)</value>
|
||||
<value>انتخاب گره فعال (Enter)</value>
|
||||
</data>
|
||||
<data name="menuRemoteBackup" xml:space="preserve">
|
||||
<value>Backup to remote (WebDAV)</value>
|
||||
<value>پشتیبان گیری از راه دور (WebDAV)</value>
|
||||
</data>
|
||||
<data name="menuRemoteRestore" xml:space="preserve">
|
||||
<value>Restore from remote (WebDAV)</value>
|
||||
<value>بازیابی از راه دور (WebDAV)</value>
|
||||
</data>
|
||||
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
|
||||
<value>Default domain strategy for outbound</value>
|
||||
<value>استراتژی دامنه پیش فرض برای خروجی</value>
|
||||
</data>
|
||||
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||
<value>Multi-Server lowest latency</value>
|
||||
<value>کمترین تأخیر چند سروره</value>
|
||||
</data>
|
||||
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
|
||||
<value>Main layout orientation(Require restart)</value>
|
||||
<value>جهت چیدمان اصلی (نیاز به راه اندازی مجدد)</value>
|
||||
</data>
|
||||
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
|
||||
<value>Multi-server load balancing</value>
|
||||
<value>تعادل بار چند سروره</value>
|
||||
</data>
|
||||
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
|
||||
<value>Outbound DNS address</value>
|
||||
<value>آدرس DNS خروجی</value>
|
||||
</data>
|
||||
<data name="menuProfileAutofitColumnWidth" xml:space="preserve">
|
||||
<value>Auto column width adjustment</value>
|
||||
<value>تنظیم خودکار عرض ستون</value>
|
||||
</data>
|
||||
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
|
||||
<value>Export Base64-encoded Share Links to Clipboard</value>
|
||||
<value>صادر کردن پیوندهای اشتراک گذاری کدگذاری شده با Base64 به کلیپ بورد</value>
|
||||
</data>
|
||||
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
||||
<value>Export selected server for complete configuration to clipboard</value>
|
||||
<value>صادر کردن سرور انتخاب شده برای پیکربندی کامل به کلیپ بورد</value>
|
||||
</data>
|
||||
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
||||
<value>Show or hide the main window</value>
|
||||
<value>نمایش یا پنهان کردن پنجره اصلی</value>
|
||||
</data>
|
||||
<data name="UpdateStandalonePackageTip" xml:space="preserve">
|
||||
<value>You are currently running a standalone package, please manually download the SelfContained.7z file to unzip and overwrite it!</value>
|
||||
<value>شما در حال حاضر در حال اجرای یک بسته مستقل هستید، لطفاً فایل SelfContained.7z را به صورت دستی دانلود کنید تا آن را از حالت فشرده خارج کرده و بازنویسی کنید!</value>
|
||||
</data>
|
||||
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||
<value>Custom config socks port</value>
|
||||
<value>پیکربندی سفارشی ساکس پورت</value>
|
||||
</data>
|
||||
<data name="menuBackupAndRestore" xml:space="preserve">
|
||||
<value>Backup and Restore</value>
|
||||
<value>پشتیبان گیری و بازیابی</value>
|
||||
</data>
|
||||
<data name="menuLocalBackup" xml:space="preserve">
|
||||
<value>Backup to local</value>
|
||||
<value>پشتیبان گیری به محلی</value>
|
||||
</data>
|
||||
<data name="menuLocalRestore" xml:space="preserve">
|
||||
<value>Restore from local</value>
|
||||
<value>بازیابی از محلی</value>
|
||||
</data>
|
||||
<data name="menuLocalBackupAndRestore" xml:space="preserve">
|
||||
<value>Local</value>
|
||||
<value>محلی</value>
|
||||
</data>
|
||||
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
|
||||
<value>Remote (WebDAV)</value>
|
||||
<value>از راه دور (WebDAV)</value>
|
||||
</data>
|
||||
<data name="LvWebDavUrl" xml:space="preserve">
|
||||
<value>WebDav Url</value>
|
||||
<value>آدرس اینترنتی WebDav</value>
|
||||
</data>
|
||||
<data name="LvWebDavUserName" xml:space="preserve">
|
||||
<value>WebDav User Name</value>
|
||||
<value>نام کاربری WebDav</value>
|
||||
</data>
|
||||
<data name="LvWebDavPassword" xml:space="preserve">
|
||||
<value>WebDav Password</value>
|
||||
<value>پسورد WebDav</value>
|
||||
</data>
|
||||
<data name="LvWebDavCheck" xml:space="preserve">
|
||||
<value>WebDav Check</value>
|
||||
<value>چک کردن WebDav</value>
|
||||
</data>
|
||||
<data name="LvWebDavDirName" xml:space="preserve">
|
||||
<value>Remote folder name (optional)</value>
|
||||
<value>نام پوشه راه دور (اختیاری)</value>
|
||||
</data>
|
||||
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
|
||||
<value>Invalid backup file</value>
|
||||
<value>فایل پشتیبان نامعتبر است</value>
|
||||
</data>
|
||||
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
|
||||
<value>Host filter</value>
|
||||
</data>
|
||||
<data name="TipActiveServer" xml:space="preserve">
|
||||
<value>Active</value>
|
||||
<value>فعال سازی</value>
|
||||
</data>
|
||||
<data name="menuStorageUI" xml:space="preserve">
|
||||
<value>Save Interface Layout</value>
|
||||
<value>ذخیره طرح رابط</value>
|
||||
</data>
|
||||
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
|
||||
<value>Geo files source (optional)</value>
|
||||
<value>منبع فایل های جغرافیایی (اختیاری)</value>
|
||||
</data>
|
||||
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
|
||||
<value>sing-box ruleset files source (optional)</value>
|
||||
<value>منبع فایل های مجموعه قوانین sing-box (اختیاری)</value>
|
||||
</data>
|
||||
<data name="UpgradeAppNotExistTip" xml:space="preserve">
|
||||
<value>UpgradeApp does not exist</value>
|
||||
<value>برنامه ارتقا وجود ندارد</value>
|
||||
</data>
|
||||
<data name="TbSettingsRoutingRulesSource" xml:space="preserve">
|
||||
<value>Routing rules source (optional)</value>
|
||||
<value>منبع قوانین مسیریابی (اختیاری)</value>
|
||||
</data>
|
||||
<data name="menuRegionalPresets" xml:space="preserve">
|
||||
<value>Regional presets setting</value>
|
||||
<value>تنظیمات از پیش تعیین شده منطقه ای</value>
|
||||
</data>
|
||||
<data name="menuRegionalPresetsDefault" xml:space="preserve">
|
||||
<value>Default</value>
|
||||
<value>پیش فرض</value>
|
||||
</data>
|
||||
<data name="menuRegionalPresetsRussia" xml:space="preserve">
|
||||
<value>Russia</value>
|
||||
<value>روسیه</value>
|
||||
</data>
|
||||
<data name="menuRegionalPresetsIran" xml:space="preserve">
|
||||
<value>ایران</value>
|
||||
</data>
|
||||
<data name="TbSettingsChinaUserTip" xml:space="preserve">
|
||||
<value>Users in China region can ignore this item</value>
|
||||
<value>کاربران در منطقه چین می توانند این مورد را نادیده بگیرند</value>
|
||||
</data>
|
||||
<data name="menuAddServerViaImage" xml:space="preserve">
|
||||
<value>Scan QR code in the image</value>
|
||||
<value>اسکن کردن QRcode موجود در تصویر</value>
|
||||
</data>
|
||||
<data name="InvalidUrlTip" xml:space="preserve">
|
||||
<value>Invalid address (Url)</value>
|
||||
<value>آدرس نامعتبر (آدرس اینترنتی)</value>
|
||||
</data>
|
||||
<data name="InsecureUrlProtocol" xml:space="preserve">
|
||||
<value>Please do not use the insecure HTTP protocol subscription address</value>
|
||||
<value>لطفاً از آدرس اشتراک پروتکل HTTP ناامن استفاده نکنید</value>
|
||||
</data>
|
||||
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
||||
<value>Install the font to the system and restart the settings</value>
|
||||
<value>فونت را روی سیستم نصب کنید و تنظیمات را مجددا راه اندازی کنید</value>
|
||||
</data>
|
||||
<data name="menuExitTips" xml:space="preserve">
|
||||
<value>Are you sure to exit?</value>
|
||||
<value>آیا مطمئن هستید که خارج می شوید؟</value>
|
||||
</data>
|
||||
<data name="LvMemo" xml:space="preserve">
|
||||
<value>Remarks Memo</value>
|
||||
<value>یادداشت ملاحظات</value>
|
||||
</data>
|
||||
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
|
||||
<value>Enable logging to file</value>
|
||||
<value>فعال کردن ورود به فایل</value>
|
||||
</data>
|
||||
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
|
||||
<value>Updates are not enabled, skip this subscription</value>
|
||||
<value>به روز رسانی ها فعال نیستند، از این اشتراک رد شوید</value>
|
||||
</data>
|
||||
<data name="menuRebootAsAdmin" xml:space="preserve">
|
||||
<value>Restart as Administrator</value>
|
||||
<value>به عنوان مدیر راه اندازی مجدد</value>
|
||||
</data>
|
||||
<data name="LvMoreUrl" xml:space="preserve">
|
||||
<value>More URLs, separated by commas; Subscription conversion will be invalid</value>
|
||||
<value>نشانیهای وب بیشتر که با کاما از هم جدا شدهاند. تبدیل اشتراک نامعتبر خواهد بود</value>
|
||||
</data>
|
||||
<data name="SpeedDisplayText" xml:space="preserve">
|
||||
<value>{0} : {1}/s↑ | {2}/s↓</value>
|
||||
</data>
|
||||
<data name="LvAutoUpdateInterval" xml:space="preserve">
|
||||
<value>Automatic update interval (minutes)</value>
|
||||
<value>فاصله به روز رسانی خودکار (دقیقه)</value>
|
||||
</data>
|
||||
<data name="LvConvertTarget" xml:space="preserve">
|
||||
<value>Convert target type</value>
|
||||
<value>تبدیل نوع هدف</value>
|
||||
</data>
|
||||
<data name="LvConvertTargetTip" xml:space="preserve">
|
||||
<value>Please leave blank if no conversion is required</value>
|
||||
<value>اگر نیازی به تبدیل نیست، لطفاً خالی بگذارید</value>
|
||||
</data>
|
||||
<data name="TipDisplayLog" xml:space="preserve">
|
||||
<value>Please turn off when there is an abnormal disconnection</value>
|
||||
<value>لطفاً در صورت قطع غیرعادی آن را خاموش کنید</value>
|
||||
</data>
|
||||
<data name="menuDNSSetting" xml:space="preserve">
|
||||
<value>DNS Settings</value>
|
||||
<value>تنظیمات DNS</value>
|
||||
</data>
|
||||
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
|
||||
<value>Please fill in DNS Structure, Click to view the document</value>
|
||||
<value>لطفا ساختار DNS را پر کنید، برای مشاهده سند کلیک کنید</value>
|
||||
</data>
|
||||
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
|
||||
<value>Click to import default DNS config</value>
|
||||
<value>برای وارد کردن تنظیمات پیشفرض DNS کلیک کنید</value>
|
||||
</data>
|
||||
<data name="TbdomainStrategy4Singbox" xml:space="preserve">
|
||||
<value>sing-box domain strategy</value>
|
||||
<value>استراتژی دامنه sing-box</value>
|
||||
</data>
|
||||
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
|
||||
<value>sing-box Mux Protocol</value>
|
||||
<value>پروتکل sing-box Mux</value>
|
||||
</data>
|
||||
<data name="TbRoutingRuleProcess" xml:space="preserve">
|
||||
<value>Full process name (Tun mode)</value>
|
||||
<value>نام کامل فرانید (حالت Tun)</value>
|
||||
</data>
|
||||
<data name="TbRoutingRuleIP" xml:space="preserve">
|
||||
<value>IP or IP CIDR</value>
|
||||
</data>
|
||||
<data name="TbRoutingRuleDomain" xml:space="preserve">
|
||||
<value>Domain</value>
|
||||
<value>دامنه</value>
|
||||
</data>
|
||||
<data name="TbSettingsCoreDnsSingbox" xml:space="preserve">
|
||||
<value>sing-box DNS settings</value>
|
||||
<value>تنظیمات DNS sing-box</value>
|
||||
</data>
|
||||
<data name="SpeedtestingWait" xml:space="preserve">
|
||||
<value>Waiting for testing (press ESC to terminate)...</value>
|
||||
<value>در انتظار آزمایش (برای پایان دادن به ESC فشار دهید)...</value>
|
||||
</data>
|
||||
<data name="TbSpiderX" xml:space="preserve">
|
||||
<value>SpiderX</value>
|
||||
@@ -1214,52 +1217,52 @@
|
||||
<value>ShortId</value>
|
||||
</data>
|
||||
<data name="menuMoveToGroup" xml:space="preserve">
|
||||
<value>Move to group</value>
|
||||
<value>انتقال به گروه</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||
<value>Enable Server Drag Drop Sort(Require restart)</value>
|
||||
<value>فعال کردن مرتب سازی با کشیدن سرور (نیاز به راه اندازی مجدد)</value>
|
||||
</data>
|
||||
<data name="TbAutoRefresh" xml:space="preserve">
|
||||
<value>AutoRefresh</value>
|
||||
<value>بازخوانی خودکار</value>
|
||||
</data>
|
||||
<data name="SpeedtestingSkip" xml:space="preserve">
|
||||
<value>Skip test</value>
|
||||
<value>رد شدن از آزمون</value>
|
||||
</data>
|
||||
<data name="menuEditServer" xml:space="preserve">
|
||||
<value>Edit Server (Ctrl+D)</value>
|
||||
<value>ویرایش سرور (Ctrl+D)</value>
|
||||
</data>
|
||||
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
|
||||
<value>Double-click server make active</value>
|
||||
<value>روی server make active دوبار کلیک کنید</value>
|
||||
</data>
|
||||
<data name="SpeedtestingCompleted" xml:space="preserve">
|
||||
<value>Test completed</value>
|
||||
<value>تست تکمیل شد</value>
|
||||
</data>
|
||||
<data name="TbSettingsDefFingerprint" xml:space="preserve">
|
||||
<value>Default TLS fingerprint</value>
|
||||
<value>اثر انگشت tls پیش فرض</value>
|
||||
</data>
|
||||
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
|
||||
<value>FontFamily(Require restart)</value>
|
||||
<value>FontFamily (نیاز به راه اندازی مجدد)</value>
|
||||
</data>
|
||||
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
||||
<value>Copy the font TTF/TTC file to the directory guiFonts, restart the settings</value>
|
||||
<value>فایل TTF/TTC فونت را در دایرکتوری guiFonts کپی کنید، تنظیمات را مجددا راه اندازی کنید</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||
<value>http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6;</value>
|
||||
<value>پورت Pac = +3; پورت Xray API = +4; پورت mihomo API = +5;</value>
|
||||
</data>
|
||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||
<value>Set this with admin privileges, get admin privileges after startup</value>
|
||||
<value>این را با امتیازات ادمین تنظیم کنید، پس از راه اندازی، امتیازات مدیر را دریافت کنید</value>
|
||||
</data>
|
||||
<data name="TbSettingsFontSize" xml:space="preserve">
|
||||
<value>Font Size</value>
|
||||
<value>اندازه فونت</value>
|
||||
</data>
|
||||
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
||||
<value>SpeedTest Single Timeout Value</value>
|
||||
<value>یمقدار تاخیر تست سرعت منفرد</value>
|
||||
</data>
|
||||
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
||||
<value>SpeedTest URL</value>
|
||||
<value>/آدرس اینترنتی SpeedTest</value>
|
||||
</data>
|
||||
<data name="menuMoveTo" xml:space="preserve">
|
||||
<value>Move up and down</value>
|
||||
<value>بالا و پایین حرکت کنید</value>
|
||||
</data>
|
||||
<data name="TbPublicKey" xml:space="preserve">
|
||||
<value>PublicKey</value>
|
||||
@@ -1268,46 +1271,46 @@
|
||||
<value>Add [Hysteria2] server</value>
|
||||
</data>
|
||||
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
||||
<value>Hysteria Max bandwidth (Up/Dw)</value>
|
||||
<value>حداکتر پهنای باند هیستریا (آپلود/دانلود)</value>
|
||||
</data>
|
||||
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
|
||||
<value>Follow System Theme</value>
|
||||
<value>دنبال کردن تم سیستم</value>
|
||||
</data>
|
||||
<data name="menuAddTuicServer" xml:space="preserve">
|
||||
<value>Add [TUIC] server</value>
|
||||
<value>افزودن سرور [TUIC]</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
|
||||
<value>Updating subscription, only determine remarks exists</value>
|
||||
<value>اشتراک در حال بهروزرسانی، فقط مشخص کنید که ملاحظاتی وجود دارد</value>
|
||||
</data>
|
||||
<data name="menuProxiesReload" xml:space="preserve">
|
||||
<value>Refresh Proxies</value>
|
||||
<value>تازه سازی پروکسی ها</value>
|
||||
</data>
|
||||
<data name="TbSortingNetwork" xml:space="preserve">
|
||||
<value>Network</value>
|
||||
<value>شبکه</value>
|
||||
</data>
|
||||
<data name="TbSortingType" xml:space="preserve">
|
||||
<value>Type</value>
|
||||
<value>نوع</value>
|
||||
</data>
|
||||
<data name="TransportRequestHostTip5" xml:space="preserve">
|
||||
<value>*grpc Authority</value>
|
||||
</data>
|
||||
<data name="menuAddHttpServer" xml:space="preserve">
|
||||
<value>Add [HTTP] server</value>
|
||||
<value>افزودن سرور [HTTP]</value>
|
||||
</data>
|
||||
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
|
||||
<value>Speed Ping Test URL</value>
|
||||
<value>آدرس اینترنتی تست پینگ سرعت</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
|
||||
<value>از Xray استفاده کنید و حالت non-Tun را فعال کنید، که با پراکسی قبلی گروه در تضاد است</value>
|
||||
</data>
|
||||
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
|
||||
<value>Custom the rule-set of sing-box</value>
|
||||
<value>سفارش سازی مجموعه قوانین از sing box</value>
|
||||
</data>
|
||||
<data name="NeedRebootTips" xml:space="preserve">
|
||||
<value>Successful operation. Click the settings menu to reboot the app.</value>
|
||||
<value>عملکرد موفقیت آمیز بود، روی منوی تنظیمات کلیک کنید تا برنامه راه اندازی مجدد شود.</value>
|
||||
</data>
|
||||
<data name="menuOpenTheFileLocation" xml:space="preserve">
|
||||
<value>Open the storage location</value>
|
||||
<value>باز کردن محل ذخیره سازی</value>
|
||||
</data>
|
||||
<data name="TbSortingChain" xml:space="preserve">
|
||||
<value>Chain</value>
|
||||
@@ -1316,72 +1319,87 @@
|
||||
<value>Host</value>
|
||||
</data>
|
||||
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
|
||||
<value>Use System Hosts</value>
|
||||
<value>استفاده کردن از System Hosts</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||
<value>Enable fragment</value>
|
||||
<value>فعال کردن فرگمنت</value>
|
||||
</data>
|
||||
<data name="TbAutoScrollToEnd" xml:space="preserve">
|
||||
<value>Auto ScrollToEnd</value>
|
||||
<value>خودکار ScrollToEnd</value>
|
||||
</data>
|
||||
<data name="SpeedtestingStop" xml:space="preserve">
|
||||
<value>Test terminating...</value>
|
||||
<value>پایان تست...</value>
|
||||
</data>
|
||||
<data name="LvNextProfile" xml:space="preserve">
|
||||
<value>Next proxy remarks</value>
|
||||
</data>
|
||||
<data name="TbPath7" xml:space="preserve">
|
||||
<value>obfs password</value>
|
||||
<value>پسورد obfs</value>
|
||||
</data>
|
||||
<data name="TbHeaderType8" xml:space="preserve">
|
||||
<value>Congestion control</value>
|
||||
<value>کنترل تراکم</value>
|
||||
</data>
|
||||
<data name="LvPrevProfile" xml:space="preserve">
|
||||
<value>Previous proxy remarks</value>
|
||||
</data>
|
||||
<data name="TbLocalAddress" xml:space="preserve">
|
||||
<value>Address(Ip,Ipv6)</value>
|
||||
<value>آدرس (IP, IPv6)</value>
|
||||
</data>
|
||||
<data name="TbReserved" xml:space="preserve">
|
||||
<value>Reserved(2,3,4)</value>
|
||||
</data>
|
||||
<data name="TbPrivateKey" xml:space="preserve">
|
||||
<value>PrivateKey</value>
|
||||
<value>کلید خصوصی</value>
|
||||
</data>
|
||||
<data name="menuAddWireguardServer" xml:space="preserve">
|
||||
<value>Add [WireGuard] server</value>
|
||||
<value>افزودن سرور [WireGuard]</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
||||
<value>Enable IPv6 Address</value>
|
||||
<value>فعال سازی آدرس IPv6</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||
<value>Enable additional Inbound</value>
|
||||
<value>فعال سازی additional Inbound</value>
|
||||
</data>
|
||||
<data name="LvPrevProfileTip" xml:space="preserve">
|
||||
<value>Please make sure the remarks exists and is unique</value>
|
||||
<value>لطفاً مطمئن شوید که ملاحظات وجود دارد و منحصر به فرد است</value>
|
||||
</data>
|
||||
<data name="TbRuleMatchingTips" xml:space="preserve">
|
||||
<value>(Domain or IP or ProcName) and Port and Protocol and InboundTag => OutboundTag</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
|
||||
<value>Linux system sudo password</value>
|
||||
<value>رمز عبور sudo سیستم</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||
<value>The password is encrypted and stored only in local files.</value>
|
||||
<value>رمز عبور رمزگذاری شده و فقط در فایل های محلی ذخیره می شود.</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||
<value>Please set the sudo password in Tun mode settings first</value>
|
||||
<value>لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
|
||||
<value>Please do not run this app with sudo</value>
|
||||
<value>لطفا این برنامه را با sudo اجرا نکنید</value>
|
||||
</data>
|
||||
<data name="TransportHeaderTypeTip5" xml:space="preserve">
|
||||
<value>*xhttp mode</value>
|
||||
<value>*حالت xhttp</value>
|
||||
</data>
|
||||
<data name="TransportExtraTip" xml:space="preserve">
|
||||
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
|
||||
<value>جیسون خام XHTTP Extra, فرمت: { XHTTPObject }</value>
|
||||
</data>
|
||||
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
||||
<value>Hide to tray when closing the window</value>
|
||||
<value>هنگام بستن پنجره در سینی پنهان شوید</value>
|
||||
</data>
|
||||
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
|
||||
<value>تعداد در هر زمان برای دسته خودکار در طول تست سرعت (حداکثر 1000)</value>
|
||||
</data>
|
||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||
<value>استثنا:از سرور پروکسی برای آدرس ها، با کاما (،) استفاده نکنید</value>
|
||||
</data>
|
||||
<data name="TbSettingsDestOverride" xml:space="preserve">
|
||||
<value>نوع Sniffing</value>
|
||||
</data>
|
||||
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
|
||||
<value>فعال کردن دومین پورت ترکیبی</value>
|
||||
</data>
|
||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||
<value>socks:پورت محلی، socks2: پورت دوم محلی، socks3: پورت LAN</value>
|
||||
</data>
|
||||
</root>
|
||||
1405
v2rayN/ServiceLib/Resx/ResUI.hu.resx
Normal file
1405
v2rayN/ServiceLib/Resx/ResUI.hu.resx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -755,7 +755,7 @@
|
||||
<value>Turn on Sniffing</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPort" xml:space="preserve">
|
||||
<value>SOCKS Port</value>
|
||||
<value>Mixed Port</value>
|
||||
</data>
|
||||
<data name="TbSettingsStartBoot" xml:space="preserve">
|
||||
<value>Start on boot</value>
|
||||
@@ -992,7 +992,7 @@
|
||||
<value>Copy the font TTF/TTC file to the directory guiFonts, restart the settings</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||
<value>http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6;</value>
|
||||
<value>Pac port = +3; Xray API port = +4; mihomo API port = +5;</value>
|
||||
</data>
|
||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||
<value>Set this with admin privileges, get admin privileges after startup</value>
|
||||
@@ -1342,6 +1342,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>
|
||||
@@ -1364,7 +1367,7 @@
|
||||
<value>Remarks Memo</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
|
||||
<value>Linux system sudo password</value>
|
||||
<value>System sudo password</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||
<value>The password is encrypted and stored only in local files.</value>
|
||||
@@ -1384,4 +1387,19 @@
|
||||
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
||||
<value>Hide to tray when closing the window</value>
|
||||
</data>
|
||||
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
|
||||
<value>Number per time for auto batch during speedtest(max 1000)</value>
|
||||
</data>
|
||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||
<value>Exception. Do not use proxy server for addresses,with a comma (,)</value>
|
||||
</data>
|
||||
<data name="TbSettingsDestOverride" xml:space="preserve">
|
||||
<value>Sniffing type</value>
|
||||
</data>
|
||||
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
|
||||
<value>Enable second mixed port</value>
|
||||
</data>
|
||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||
<value>socks: local port, socks2: second local port, socks3: LAN port</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -761,7 +761,7 @@
|
||||
<value>Включить сниффинг</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPort" xml:space="preserve">
|
||||
<value>Порт Socks</value>
|
||||
<value>Mixed Port</value>
|
||||
</data>
|
||||
<data name="TbSettingsStartBoot" xml:space="preserve">
|
||||
<value>Автозапуск</value>
|
||||
@@ -1039,6 +1039,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>
|
||||
@@ -1310,7 +1313,7 @@
|
||||
<value>Move up and down</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||
<value>http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6;</value>
|
||||
<value>Pac port = +3; Xray API port = +4; mihomo API port = +5;</value>
|
||||
</data>
|
||||
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
||||
<value>Install the font to the system and restart the settings</value>
|
||||
@@ -1364,7 +1367,7 @@
|
||||
<value>Remote (WebDAV)</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
|
||||
<value>Linux system sudo password</value>
|
||||
<value>System sudo password</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||
<value>The password is encrypted and stored only in local files.</value>
|
||||
@@ -1384,4 +1387,19 @@
|
||||
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
||||
<value>Hide to tray when closing the window</value>
|
||||
</data>
|
||||
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
|
||||
<value>Number per time for auto batch during speedtest(max 1000)</value>
|
||||
</data>
|
||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||
<value>Exception. Do not use proxy server for addresses,with a comma (,)</value>
|
||||
</data>
|
||||
<data name="TbSettingsDestOverride" xml:space="preserve">
|
||||
<value>Sniffing type</value>
|
||||
</data>
|
||||
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
|
||||
<value>Enable second mixed port</value>
|
||||
</data>
|
||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||
<value>socks: local port, socks2: second local port, socks3: LAN port</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -755,7 +755,7 @@
|
||||
<value>开启流量探测</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPort" xml:space="preserve">
|
||||
<value>本地socks监听端口</value>
|
||||
<value>本地混合监听端口</value>
|
||||
</data>
|
||||
<data name="TbSettingsStartBoot" xml:space="preserve">
|
||||
<value>开机启动(可能会不成功)</value>
|
||||
@@ -992,7 +992,7 @@
|
||||
<value>拷贝字体TTF/TTC文件到目录guiFonts,重启设置</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||
<value>http端口= +1;Pac端口= +4;*ray API端口= +5;mihomo API端口= +6;</value>
|
||||
<value>Pac端口= +3;Xray API端口= +4;mihomo API端口= +5;</value>
|
||||
</data>
|
||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||
<value>以管理员权限设置此项,在启动后获得管理员权限</value>
|
||||
@@ -1342,6 +1342,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>
|
||||
@@ -1361,7 +1364,7 @@
|
||||
<value>备注备忘</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
|
||||
<value>Linux系统的sudo密码</value>
|
||||
<value>系统的sudo密码</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||
<value>密码已加密且只存储在本地文件中,无密码则每次都要输入</value>
|
||||
@@ -1381,4 +1384,19 @@
|
||||
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
||||
<value>关闭窗口时隐藏至托盘</value>
|
||||
</data>
|
||||
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
|
||||
<value>测试时自动分批的每批数量(最大1000)</value>
|
||||
</data>
|
||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||
<value>例外. 对于下列地址不使用代理配置文件:使用逗号(,)分隔</value>
|
||||
</data>
|
||||
<data name="TbSettingsDestOverride" xml:space="preserve">
|
||||
<value>流量探测类型</value>
|
||||
</data>
|
||||
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
|
||||
<value>开启第二个本地监听端口</value>
|
||||
</data>
|
||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||
<value>socks:本地端口,socks2:第二个本地端口,socks3:局域网端口</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -755,7 +755,7 @@
|
||||
<value>開啟流量探測</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPort" xml:space="preserve">
|
||||
<value>本機SOCKS偵聽埠</value>
|
||||
<value>本機混合偵聽埠</value>
|
||||
</data>
|
||||
<data name="TbSettingsStartBoot" xml:space="preserve">
|
||||
<value>開機啟動(可能會不成功)</value>
|
||||
@@ -992,7 +992,7 @@
|
||||
<value>複製字型TTF/TTC檔案到目錄guiFonts,重啟設定</value>
|
||||
</data>
|
||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||
<value>http連接埠= +1;Pac連接埠= +4;*ray API連接埠= +5;mihomo API連接埠= +6;</value>
|
||||
<value>Pac連接埠= +3;Xray API連接埠= +4;mihomo API連接埠= +5;</value>
|
||||
</data>
|
||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||
<value>以管理員權限設定此項,在啟動後獲得管理員權限</value>
|
||||
@@ -1222,6 +1222,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>
|
||||
@@ -1361,7 +1364,7 @@
|
||||
<value>混淆密碼(obfs password)</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
|
||||
<value>Linux系統的sudo密碼</value>
|
||||
<value>系統的sudo密碼</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||
<value>密碼已加密且只儲存在本機檔案中,無密碼則每次都要輸入</value>
|
||||
@@ -1381,4 +1384,19 @@
|
||||
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
||||
<value>關閉視窗時隱藏至托盤</value>
|
||||
</data>
|
||||
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
|
||||
<value>測試時自動分批的每批數量(最大1000)</value>
|
||||
</data>
|
||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||
<value>例外. 對於下列位址不使用代理設定檔:使用逗號(,)分隔</value>
|
||||
</data>
|
||||
<data name="TbSettingsDestOverride" xml:space="preserve">
|
||||
<value>流量探測類型</value>
|
||||
</data>
|
||||
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
|
||||
<value>開啟第二個本機監聽埠</value>
|
||||
</data>
|
||||
<data name="TbRoutingInboundTagTips" xml:space="preserve">
|
||||
<value>socks:本地端口,socks2:第二個本地端口,socks3:區域網路端口</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,149 +1,156 @@
|
||||
[
|
||||
{
|
||||
"remarks": "绕过bittorrent",
|
||||
"outboundTag": "direct",
|
||||
"protocol": [
|
||||
"bittorrent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "Google cn",
|
||||
"outboundTag": "proxy",
|
||||
"domain": [
|
||||
"domain:googleapis.cn",
|
||||
"domain:gstatic.com"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "阻断udp443",
|
||||
"outboundTag": "block",
|
||||
"port": "443",
|
||||
"network": "udp"
|
||||
},
|
||||
{
|
||||
"remarks": "阻断广告",
|
||||
"outboundTag": "block",
|
||||
"domain": [
|
||||
"geosite:category-ads-all"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "绕过局域网IP",
|
||||
"outboundTag": "direct",
|
||||
"ip": [
|
||||
"geoip:private"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "绕过局域网域名",
|
||||
"outboundTag": "direct",
|
||||
"domain": [
|
||||
"geosite:private"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "代理海外公共DNSIP",
|
||||
"outboundTag": "proxy",
|
||||
"ip": [
|
||||
"1.1.1.1",
|
||||
"1.0.0.1",
|
||||
"2606:4700:4700::1111",
|
||||
"2606:4700:4700::1001",
|
||||
"1.1.1.2",
|
||||
"1.0.0.2",
|
||||
"2606:4700:4700::1112",
|
||||
"2606:4700:4700::1002",
|
||||
"1.1.1.3",
|
||||
"1.0.0.3",
|
||||
"2606:4700:4700::1113",
|
||||
"2606:4700:4700::1003",
|
||||
"8.8.8.8",
|
||||
"8.8.4.4",
|
||||
"2001:4860:4860::8888",
|
||||
"2001:4860:4860::8844",
|
||||
"94.140.14.14",
|
||||
"94.140.15.15",
|
||||
"2a10:50c0::ad1:ff",
|
||||
"2a10:50c0::ad2:ff",
|
||||
"94.140.14.15",
|
||||
"94.140.15.16",
|
||||
"2a10:50c0::bad1:ff",
|
||||
"2a10:50c0::bad2:ff",
|
||||
"94.140.14.140",
|
||||
"94.140.14.141",
|
||||
"2a10:50c0::1:ff",
|
||||
"2a10:50c0::2:ff",
|
||||
"208.67.222.222",
|
||||
"208.67.220.220",
|
||||
"2620:119:35::35",
|
||||
"2620:119:53::53",
|
||||
"208.67.222.123",
|
||||
"208.67.220.123",
|
||||
"2620:119:35::123",
|
||||
"2620:119:53::123",
|
||||
"9.9.9.9",
|
||||
"149.112.112.112",
|
||||
"2620:fe::9",
|
||||
"2620:fe::fe",
|
||||
"9.9.9.11",
|
||||
"149.112.112.11",
|
||||
"2620:fe::11",
|
||||
"2620:fe::fe:11",
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10",
|
||||
"77.88.8.8",
|
||||
"77.88.8.1",
|
||||
"2a02:6b8::feed:0ff",
|
||||
"2a02:6b8:0:1::feed:0ff",
|
||||
"77.88.8.88",
|
||||
"77.88.8.2",
|
||||
"2a02:6b8::feed:bad",
|
||||
"2a02:6b8:0:1::feed:bad",
|
||||
"77.88.8.7",
|
||||
"77.88.8.3",
|
||||
"2a02:6b8::feed:a11",
|
||||
"2a02:6b8:0:1::feed:a11"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "代理海外公共DNS域名",
|
||||
"outboundTag": "proxy",
|
||||
"domain": [
|
||||
"domain:cloudflare-dns.com",
|
||||
"domain:one.one.one.one",
|
||||
"domain:dns.google",
|
||||
"domain:adguard-dns.com",
|
||||
"domain:opendns.com",
|
||||
"domain:umbrella.com",
|
||||
"domain:quad9.net",
|
||||
"domain:yandex.net"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "代理IP",
|
||||
"outboundTag": "proxy",
|
||||
"ip": [
|
||||
"geoip:facebook",
|
||||
"geoip:fastly",
|
||||
"geoip:google",
|
||||
"geoip:netflix",
|
||||
"geoip:telegram",
|
||||
"geoip:twitter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "代理GFW",
|
||||
"outboundTag": "proxy",
|
||||
"domain": [
|
||||
"geosite:gfw",
|
||||
"geosite:greatfire"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "最终直连",
|
||||
"port": "0-65535",
|
||||
"outboundTag": "direct"
|
||||
}
|
||||
{
|
||||
"remarks": "绕过bittorrent",
|
||||
"outboundTag": "direct",
|
||||
"protocol": [
|
||||
"bittorrent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "api.ip.sb",
|
||||
"outboundTag": "proxy",
|
||||
"domain": [
|
||||
"api.ip.sb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "Google cn",
|
||||
"outboundTag": "proxy",
|
||||
"domain": [
|
||||
"domain:googleapis.cn",
|
||||
"domain:gstatic.com"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "阻断udp443",
|
||||
"outboundTag": "block",
|
||||
"port": "443",
|
||||
"network": "udp"
|
||||
},
|
||||
{
|
||||
"remarks": "阻断广告",
|
||||
"outboundTag": "block",
|
||||
"domain": [
|
||||
"geosite:category-ads-all"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "绕过局域网IP",
|
||||
"outboundTag": "direct",
|
||||
"ip": [
|
||||
"geoip:private"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "绕过局域网域名",
|
||||
"outboundTag": "direct",
|
||||
"domain": [
|
||||
"geosite:private"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "代理海外公共DNSIP",
|
||||
"outboundTag": "proxy",
|
||||
"ip": [
|
||||
"1.1.1.1",
|
||||
"1.0.0.1",
|
||||
"2606:4700:4700::1111",
|
||||
"2606:4700:4700::1001",
|
||||
"1.1.1.2",
|
||||
"1.0.0.2",
|
||||
"2606:4700:4700::1112",
|
||||
"2606:4700:4700::1002",
|
||||
"1.1.1.3",
|
||||
"1.0.0.3",
|
||||
"2606:4700:4700::1113",
|
||||
"2606:4700:4700::1003",
|
||||
"8.8.8.8",
|
||||
"8.8.4.4",
|
||||
"2001:4860:4860::8888",
|
||||
"2001:4860:4860::8844",
|
||||
"94.140.14.14",
|
||||
"94.140.15.15",
|
||||
"2a10:50c0::ad1:ff",
|
||||
"2a10:50c0::ad2:ff",
|
||||
"94.140.14.15",
|
||||
"94.140.15.16",
|
||||
"2a10:50c0::bad1:ff",
|
||||
"2a10:50c0::bad2:ff",
|
||||
"94.140.14.140",
|
||||
"94.140.14.141",
|
||||
"2a10:50c0::1:ff",
|
||||
"2a10:50c0::2:ff",
|
||||
"208.67.222.222",
|
||||
"208.67.220.220",
|
||||
"2620:119:35::35",
|
||||
"2620:119:53::53",
|
||||
"208.67.222.123",
|
||||
"208.67.220.123",
|
||||
"2620:119:35::123",
|
||||
"2620:119:53::123",
|
||||
"9.9.9.9",
|
||||
"149.112.112.112",
|
||||
"2620:fe::9",
|
||||
"2620:fe::fe",
|
||||
"9.9.9.11",
|
||||
"149.112.112.11",
|
||||
"2620:fe::11",
|
||||
"2620:fe::fe:11",
|
||||
"9.9.9.10",
|
||||
"149.112.112.10",
|
||||
"2620:fe::10",
|
||||
"2620:fe::fe:10",
|
||||
"77.88.8.8",
|
||||
"77.88.8.1",
|
||||
"2a02:6b8::feed:0ff",
|
||||
"2a02:6b8:0:1::feed:0ff",
|
||||
"77.88.8.88",
|
||||
"77.88.8.2",
|
||||
"2a02:6b8::feed:bad",
|
||||
"2a02:6b8:0:1::feed:bad",
|
||||
"77.88.8.7",
|
||||
"77.88.8.3",
|
||||
"2a02:6b8::feed:a11",
|
||||
"2a02:6b8:0:1::feed:a11"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "代理海外公共DNS域名",
|
||||
"outboundTag": "proxy",
|
||||
"domain": [
|
||||
"domain:cloudflare-dns.com",
|
||||
"domain:one.one.one.one",
|
||||
"domain:dns.google",
|
||||
"domain:adguard-dns.com",
|
||||
"domain:opendns.com",
|
||||
"domain:umbrella.com",
|
||||
"domain:quad9.net",
|
||||
"domain:yandex.net"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "代理IP",
|
||||
"outboundTag": "proxy",
|
||||
"ip": [
|
||||
"geoip:facebook",
|
||||
"geoip:fastly",
|
||||
"geoip:google",
|
||||
"geoip:netflix",
|
||||
"geoip:telegram",
|
||||
"geoip:twitter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "代理GFW",
|
||||
"outboundTag": "proxy",
|
||||
"domain": [
|
||||
"geosite:gfw",
|
||||
"geosite:greatfire"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "最终直连",
|
||||
"port": "0-65535",
|
||||
"outboundTag": "direct"
|
||||
}
|
||||
]
|
||||
@@ -1,21 +0,0 @@
|
||||
[
|
||||
{
|
||||
"domain": [
|
||||
"geosite:google"
|
||||
],
|
||||
"outboundTag": "proxy"
|
||||
},
|
||||
{
|
||||
"outboundTag": "direct",
|
||||
"domain": [
|
||||
"domain:example-example.com",
|
||||
"domain:example-example2.com"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outboundTag": "block",
|
||||
"domain": [
|
||||
"geosite:category-ads-all"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,29 +0,0 @@
|
||||
[
|
||||
{
|
||||
"remarks": "block",
|
||||
"outboundTag": "block",
|
||||
"domain": [
|
||||
"geosite:category-ads-all"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "direct",
|
||||
"outboundTag": "direct",
|
||||
"domain": [
|
||||
"geosite:cn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "direct",
|
||||
"outboundTag": "direct",
|
||||
"ip": [
|
||||
"geoip:private",
|
||||
"geoip:cn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "proxy",
|
||||
"port": "0-65535",
|
||||
"outboundTag": "proxy"
|
||||
}
|
||||
]
|
||||
@@ -99,10 +99,5 @@
|
||||
"domain": [
|
||||
"geosite:cn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "最终代理",
|
||||
"port": "0-65535",
|
||||
"outboundTag": "proxy"
|
||||
}
|
||||
]
|
||||
@@ -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
@@ -4,19 +4,19 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>7.2.2</Version>
|
||||
<Version>7.5.2</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Downloader" Version="3.3.0" />
|
||||
<PackageReference Include="Downloader" Version="3.3.1" />
|
||||
<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.0" />
|
||||
<PackageReference Include="YamlDotNet" Version="16.3.0" />
|
||||
<PackageReference Include="QRCoder" Version="1.6.0" />
|
||||
<PackageReference Include="CliWrap" Version="3.6.7" />
|
||||
<PackageReference Include="CliWrap" Version="3.7.0" />
|
||||
<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" />
|
||||
@@ -28,8 +28,6 @@
|
||||
<EmbeddedResource Include="Sample\clash_tun_yaml" />
|
||||
<EmbeddedResource Include="Sample\custom_routing_black" />
|
||||
<EmbeddedResource Include="Sample\custom_routing_global" />
|
||||
<EmbeddedResource Include="Sample\custom_routing_locked" />
|
||||
<EmbeddedResource Include="Sample\custom_routing_rules" />
|
||||
<EmbeddedResource Include="Sample\custom_routing_white" />
|
||||
<EmbeddedResource Include="Sample\dns_singbox_normal" />
|
||||
<EmbeddedResource Include="Sample\dns_v2ray_normal" />
|
||||
@@ -60,6 +58,9 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Resx\ResUI.hu.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Resx\ResUI.resx">
|
||||
<SubType>Designer</SubType>
|
||||
<LastGenOutput>ResUI.Designer.cs</LastGenOutput>
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
public class CoreConfigClashService
|
||||
{
|
||||
private Config _config;
|
||||
private static readonly string _tag = "CoreConfigClashService";
|
||||
|
||||
public CoreConfigClashService(Config config)
|
||||
{
|
||||
@@ -78,17 +79,15 @@ namespace ServiceLib.Services.CoreConfig
|
||||
return ret;
|
||||
}
|
||||
|
||||
//port
|
||||
fileContent["port"] = AppHandler.Instance.GetLocalPort(EInboundProtocol.http);
|
||||
//socks-port
|
||||
fileContent["socks-port"] = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||
//mixed-port
|
||||
fileContent["mixed-port"] = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||
//log-level
|
||||
fileContent["log-level"] = GetLogLevel(_config.CoreBasicItem.Loglevel);
|
||||
|
||||
//external-controller
|
||||
fileContent["external-controller"] = $"{Global.Loopback}:{AppHandler.Instance.StatePort2}";
|
||||
//allow-lan
|
||||
if (_config.Inbound[0].AllowLANConn)
|
||||
if (_config.Inbound.First().AllowLANConn)
|
||||
{
|
||||
fileContent["allow-lan"] = "true";
|
||||
fileContent["bind-address"] = "*";
|
||||
@@ -133,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);
|
||||
@@ -153,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)
|
||||
{
|
||||
@@ -26,7 +27,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
ret.Msg = ResUI.CheckServerSettings;
|
||||
return ret;
|
||||
}
|
||||
if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.xhttp))
|
||||
if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.xhttp))
|
||||
{
|
||||
ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
|
||||
return ret;
|
||||
@@ -52,7 +53,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
|
||||
await GenInbounds(singboxConfig);
|
||||
|
||||
await GenOutbound(node, singboxConfig.outbounds[0]);
|
||||
await GenOutbound(node, singboxConfig.outbounds.First());
|
||||
|
||||
await GenMoreOutbounds(node, singboxConfig);
|
||||
|
||||
@@ -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);
|
||||
@@ -122,7 +123,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
singboxConfig.inbounds.Clear();
|
||||
singboxConfig.outbounds.RemoveAt(0);
|
||||
|
||||
var httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
|
||||
var initPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
|
||||
|
||||
foreach (var it in selecteds)
|
||||
{
|
||||
@@ -144,8 +145,8 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
|
||||
//find unused port
|
||||
var port = httpPort;
|
||||
for (int k = httpPort; k < Global.MaxPort; k++)
|
||||
var port = initPort;
|
||||
for (int k = initPort; k < Global.MaxPort; k++)
|
||||
{
|
||||
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
|
||||
{
|
||||
@@ -157,7 +158,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
//found
|
||||
port = k;
|
||||
httpPort = port + 1;
|
||||
initPort = port + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -174,7 +175,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
{
|
||||
listen = Global.Loopback,
|
||||
listen_port = port,
|
||||
type = EInboundProtocol.http.ToString(),
|
||||
type = EInboundProtocol.mixed.ToString(),
|
||||
};
|
||||
inbound.tag = inbound.type + inbound.listen_port.ToString();
|
||||
singboxConfig.inbounds.Add(inbound);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -409,7 +410,9 @@ namespace ServiceLib.Services.CoreConfig
|
||||
{
|
||||
await GenInbounds(singboxConfig);
|
||||
await GenExperimental(singboxConfig);
|
||||
JsonUtils.ToFile(singboxConfig, fileName, false);
|
||||
|
||||
var content = JsonUtils.Serialize(singboxConfig, true);
|
||||
await File.WriteAllTextAsync(fileName, content);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -430,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;
|
||||
}
|
||||
@@ -440,7 +443,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
|
||||
#region private gen function
|
||||
|
||||
public async Task<int> GenLog(SingboxConfig singboxConfig)
|
||||
private async Task<int> GenLog(SingboxConfig singboxConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -471,7 +474,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -488,15 +491,15 @@ namespace ServiceLib.Services.CoreConfig
|
||||
{
|
||||
var inbound = new Inbound4Sbox()
|
||||
{
|
||||
type = EInboundProtocol.socks.ToString(),
|
||||
type = EInboundProtocol.mixed.ToString(),
|
||||
tag = EInboundProtocol.socks.ToString(),
|
||||
listen = Global.Loopback,
|
||||
};
|
||||
singboxConfig.inbounds.Add(inbound);
|
||||
|
||||
inbound.listen_port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||
inbound.sniff = _config.Inbound[0].SniffingEnabled;
|
||||
inbound.sniff_override_destination = _config.Inbound[0].RouteOnly ? false : _config.Inbound[0].SniffingEnabled;
|
||||
inbound.sniff = _config.Inbound.First().SniffingEnabled;
|
||||
inbound.sniff_override_destination = _config.Inbound.First().RouteOnly ? false : _config.Inbound.First().SniffingEnabled;
|
||||
inbound.domain_strategy = Utils.IsNullOrEmpty(_config.RoutingBasicItem.DomainStrategy4Singbox) ? null : _config.RoutingBasicItem.DomainStrategy4Singbox;
|
||||
|
||||
var routing = await ConfigHandler.GetDefaultRouting(_config);
|
||||
@@ -505,33 +508,29 @@ namespace ServiceLib.Services.CoreConfig
|
||||
inbound.domain_strategy = routing.DomainStrategy4Singbox;
|
||||
}
|
||||
|
||||
//http
|
||||
var inbound2 = GetInbound(inbound, EInboundProtocol.http, false);
|
||||
singboxConfig.inbounds.Add(inbound2);
|
||||
|
||||
if (_config.Inbound[0].AllowLANConn)
|
||||
if (_config.Inbound.First().SecondLocalPortEnabled)
|
||||
{
|
||||
if (_config.Inbound[0].NewPort4LAN)
|
||||
var inbound2 = GetInbound(inbound, EInboundProtocol.socks2, true);
|
||||
singboxConfig.inbounds.Add(inbound2);
|
||||
}
|
||||
|
||||
if (_config.Inbound.First().AllowLANConn)
|
||||
{
|
||||
if (_config.Inbound.First().NewPort4LAN)
|
||||
{
|
||||
var inbound3 = GetInbound(inbound, EInboundProtocol.socks2, true);
|
||||
var inbound3 = GetInbound(inbound, EInboundProtocol.socks3, true);
|
||||
inbound3.listen = listen;
|
||||
singboxConfig.inbounds.Add(inbound3);
|
||||
|
||||
var inbound4 = GetInbound(inbound, EInboundProtocol.http2, false);
|
||||
inbound4.listen = listen;
|
||||
singboxConfig.inbounds.Add(inbound4);
|
||||
|
||||
//auth
|
||||
if (Utils.IsNotEmpty(_config.Inbound[0].User) && Utils.IsNotEmpty(_config.Inbound[0].Pass))
|
||||
if (Utils.IsNotEmpty(_config.Inbound.First().User) && Utils.IsNotEmpty(_config.Inbound.First().Pass))
|
||||
{
|
||||
inbound3.users = new() { new() { username = _config.Inbound[0].User, password = _config.Inbound[0].Pass } };
|
||||
inbound4.users = new() { new() { username = _config.Inbound[0].User, password = _config.Inbound[0].Pass } };
|
||||
inbound3.users = new() { new() { username = _config.Inbound.First().User, password = _config.Inbound.First().Pass } };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inbound.listen = listen;
|
||||
inbound2.listen = listen;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -540,20 +539,20 @@ namespace ServiceLib.Services.CoreConfig
|
||||
{
|
||||
if (_config.TunModeItem.Mtu <= 0)
|
||||
{
|
||||
_config.TunModeItem.Mtu = Utils.ToInt(Global.TunMtus[0]);
|
||||
_config.TunModeItem.Mtu = Utils.ToInt(Global.TunMtus.First());
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(_config.TunModeItem.Stack))
|
||||
{
|
||||
_config.TunModeItem.Stack = Global.TunStacks[0];
|
||||
_config.TunModeItem.Stack = Global.TunStacks.First();
|
||||
}
|
||||
|
||||
var tunInbound = JsonUtils.Deserialize<Inbound4Sbox>(Utils.GetEmbedText(Global.TunSingboxInboundFileName)) ?? new Inbound4Sbox { };
|
||||
tunInbound.interface_name = Utils.IsOSX()? $"utun{new Random().Next(99)}": "singbox_tun";
|
||||
tunInbound.interface_name = Utils.IsOSX() ? $"utun{new Random().Next(99)}" : "singbox_tun";
|
||||
tunInbound.mtu = _config.TunModeItem.Mtu;
|
||||
tunInbound.strict_route = _config.TunModeItem.StrictRoute;
|
||||
tunInbound.stack = _config.TunModeItem.Stack;
|
||||
tunInbound.sniff = _config.Inbound[0].SniffingEnabled;
|
||||
//tunInbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled;
|
||||
tunInbound.sniff = _config.Inbound.First().SniffingEnabled;
|
||||
//tunInbound.sniff_override_destination = _config.inbound.First().routeOnly ? false : _config.inbound.First().sniffingEnabled;
|
||||
if (_config.TunModeItem.EnableIPv6Address == false)
|
||||
{
|
||||
tunInbound.address = ["172.18.0.1/30"];
|
||||
@@ -564,7 +563,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -574,11 +573,11 @@ namespace ServiceLib.Services.CoreConfig
|
||||
var inbound = JsonUtils.DeepCopy(inItem);
|
||||
inbound.tag = protocol.ToString();
|
||||
inbound.listen_port = inItem.listen_port + (int)protocol;
|
||||
inbound.type = bSocks ? EInboundProtocol.socks.ToString() : EInboundProtocol.http.ToString();
|
||||
inbound.type = EInboundProtocol.mixed.ToString();
|
||||
return inbound;
|
||||
}
|
||||
|
||||
public async Task<int> GenOutbound(ProfileItem node, Outbound4Sbox outbound)
|
||||
private async Task<int> GenOutbound(ProfileItem node, Outbound4Sbox outbound)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -697,12 +696,12 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenOutboundMux(ProfileItem node, Outbound4Sbox outbound)
|
||||
private async Task<int> GenOutboundMux(ProfileItem node, Outbound4Sbox outbound)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -720,12 +719,12 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenOutboundTls(ProfileItem node, Outbound4Sbox outbound)
|
||||
private async Task<int> GenOutboundTls(ProfileItem node, Outbound4Sbox outbound)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -770,12 +769,12 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenOutboundTransport(ProfileItem node, Outbound4Sbox outbound)
|
||||
private async Task<int> GenOutboundTransport(ProfileItem node, Outbound4Sbox outbound)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -847,7 +846,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -867,7 +866,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
|
||||
//current proxy
|
||||
var outbound = singboxConfig.outbounds[0];
|
||||
var outbound = singboxConfig.outbounds.First();
|
||||
var txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
|
||||
|
||||
//Previous proxy
|
||||
@@ -899,7 +898,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -910,7 +909,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
try
|
||||
{
|
||||
var dnsOutbound = "dns_out";
|
||||
if (!_config.Inbound[0].SniffingEnabled)
|
||||
if (!_config.Inbound.First().SniffingEnabled)
|
||||
{
|
||||
singboxConfig.route.rules.Add(new()
|
||||
{
|
||||
@@ -971,7 +970,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1002,7 +1001,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> GenRoutingUserRule(RulesItem item, List<Rule4Sbox> rules)
|
||||
private async Task<int> GenRoutingUserRule(RulesItem item, List<Rule4Sbox> rules)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1087,7 +1086,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1160,7 +1159,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<int> GenDns(ProfileItem? node, SingboxConfig singboxConfig)
|
||||
private async Task<int> GenDns(ProfileItem? node, SingboxConfig singboxConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1186,12 +1185,12 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenDnsDomains(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem)
|
||||
private async Task<int> GenDnsDomains(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem)
|
||||
{
|
||||
var dns4Sbox = singboxConfig.dns ?? new();
|
||||
dns4Sbox.servers ??= [];
|
||||
@@ -1244,7 +1243,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenExperimental(SingboxConfig singboxConfig)
|
||||
private async Task<int> GenExperimental(SingboxConfig singboxConfig)
|
||||
{
|
||||
//if (_config.guiItem.enableStatistics)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
public class CoreConfigV2rayService
|
||||
{
|
||||
private Config _config;
|
||||
private static readonly string _tag = "CoreConfigV2rayService";
|
||||
|
||||
public CoreConfigV2rayService(Config config)
|
||||
{
|
||||
@@ -55,7 +56,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
|
||||
await GenRouting(v2rayConfig);
|
||||
|
||||
await GenOutbound(node, v2rayConfig.outbounds[0]);
|
||||
await GenOutbound(node, v2rayConfig.outbounds.First());
|
||||
|
||||
await GenMoreOutbounds(node, v2rayConfig);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -197,7 +198,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 +241,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
await GenLog(v2rayConfig);
|
||||
@@ -248,7 +249,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
v2rayConfig.outbounds.Clear();
|
||||
v2rayConfig.routing.rules.Clear();
|
||||
|
||||
var httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
|
||||
var initPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
|
||||
|
||||
foreach (var it in selecteds)
|
||||
{
|
||||
@@ -270,8 +271,8 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
|
||||
//find unused port
|
||||
var port = httpPort;
|
||||
for (var k = httpPort; k < Global.MaxPort; k++)
|
||||
var port = initPort;
|
||||
for (var k = initPort; k < Global.MaxPort; k++)
|
||||
{
|
||||
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
|
||||
{
|
||||
@@ -283,7 +284,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
//found
|
||||
port = k;
|
||||
httpPort = port + 1;
|
||||
initPort = port + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -322,7 +323,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
{
|
||||
listen = Global.Loopback,
|
||||
port = port,
|
||||
protocol = EInboundProtocol.http.ToString(),
|
||||
protocol = EInboundProtocol.socks.ToString(),
|
||||
};
|
||||
inbound.tag = inbound.protocol + inbound.port.ToString();
|
||||
v2rayConfig.inbounds.Add(inbound);
|
||||
@@ -349,7 +350,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
@@ -359,7 +360,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
|
||||
#region private gen function
|
||||
|
||||
public async Task<int> GenLog(V2rayConfig v2rayConfig)
|
||||
private async Task<int> GenLog(V2rayConfig v2rayConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -379,57 +380,51 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenInbounds(V2rayConfig v2rayConfig)
|
||||
private async Task<int> GenInbounds(V2rayConfig v2rayConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
var listen = "0.0.0.0";
|
||||
v2rayConfig.inbounds = [];
|
||||
|
||||
Inbounds4Ray? inbound = GetInbound(_config.Inbound[0], EInboundProtocol.socks, true);
|
||||
var inbound = GetInbound(_config.Inbound.First(), EInboundProtocol.socks, true);
|
||||
v2rayConfig.inbounds.Add(inbound);
|
||||
|
||||
//http
|
||||
Inbounds4Ray? inbound2 = GetInbound(_config.Inbound[0], EInboundProtocol.http, false);
|
||||
v2rayConfig.inbounds.Add(inbound2);
|
||||
|
||||
if (_config.Inbound[0].AllowLANConn)
|
||||
if (_config.Inbound.First().SecondLocalPortEnabled)
|
||||
{
|
||||
if (_config.Inbound[0].NewPort4LAN)
|
||||
var inbound2 = GetInbound(_config.Inbound.First(), EInboundProtocol.socks2, true);
|
||||
v2rayConfig.inbounds.Add(inbound2);
|
||||
}
|
||||
|
||||
if (_config.Inbound.First().AllowLANConn)
|
||||
{
|
||||
if (_config.Inbound.First().NewPort4LAN)
|
||||
{
|
||||
var inbound3 = GetInbound(_config.Inbound[0], EInboundProtocol.socks2, true);
|
||||
var inbound3 = GetInbound(_config.Inbound.First(), EInboundProtocol.socks3, true);
|
||||
inbound3.listen = listen;
|
||||
v2rayConfig.inbounds.Add(inbound3);
|
||||
|
||||
var inbound4 = GetInbound(_config.Inbound[0], EInboundProtocol.http2, false);
|
||||
inbound4.listen = listen;
|
||||
v2rayConfig.inbounds.Add(inbound4);
|
||||
|
||||
//auth
|
||||
if (Utils.IsNotEmpty(_config.Inbound[0].User) && Utils.IsNotEmpty(_config.Inbound[0].Pass))
|
||||
if (Utils.IsNotEmpty(_config.Inbound.First().User) && Utils.IsNotEmpty(_config.Inbound.First().Pass))
|
||||
{
|
||||
inbound3.settings.auth = "password";
|
||||
inbound3.settings.accounts = new List<AccountsItem4Ray> { new AccountsItem4Ray() { user = _config.Inbound[0].User, pass = _config.Inbound[0].Pass } };
|
||||
|
||||
inbound4.settings.auth = "password";
|
||||
inbound4.settings.accounts = new List<AccountsItem4Ray> { new AccountsItem4Ray() { user = _config.Inbound[0].User, pass = _config.Inbound[0].Pass } };
|
||||
inbound3.settings.accounts = new List<AccountsItem4Ray> { new AccountsItem4Ray() { user = _config.Inbound.First().User, pass = _config.Inbound.First().Pass } };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inbound.listen = listen;
|
||||
inbound2.listen = listen;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -449,7 +444,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
inbound.tag = protocol.ToString();
|
||||
inbound.port = inItem.LocalPort + (int)protocol;
|
||||
inbound.protocol = bSocks ? EInboundProtocol.socks.ToString() : EInboundProtocol.http.ToString();
|
||||
inbound.protocol = EInboundProtocol.socks.ToString();
|
||||
inbound.settings.udp = inItem.UdpEnabled;
|
||||
inbound.sniffing.enabled = inItem.SniffingEnabled;
|
||||
inbound.sniffing.destOverride = inItem.DestOverride;
|
||||
@@ -488,12 +483,12 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenRoutingUserRule(RulesItem4Ray? rule, V2rayConfig v2rayConfig)
|
||||
private async Task<int> GenRoutingUserRule(RulesItem4Ray? rule, V2rayConfig v2rayConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -566,12 +561,12 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound)
|
||||
private async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -587,7 +582,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
else
|
||||
{
|
||||
vnextItem = outbound.settings.vnext[0];
|
||||
vnextItem = outbound.settings.vnext.First();
|
||||
}
|
||||
vnextItem.address = node.Address;
|
||||
vnextItem.port = node.Port;
|
||||
@@ -600,7 +595,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
else
|
||||
{
|
||||
usersItem = vnextItem.users[0];
|
||||
usersItem = vnextItem.users.First();
|
||||
}
|
||||
//远程服务器用户ID
|
||||
usersItem.id = node.Id;
|
||||
@@ -630,7 +625,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
else
|
||||
{
|
||||
serversItem = outbound.settings.servers[0];
|
||||
serversItem = outbound.settings.servers.First();
|
||||
}
|
||||
serversItem.address = node.Address;
|
||||
serversItem.port = node.Port;
|
||||
@@ -656,7 +651,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
else
|
||||
{
|
||||
serversItem = outbound.settings.servers[0];
|
||||
serversItem = outbound.settings.servers.First();
|
||||
}
|
||||
serversItem.address = node.Address;
|
||||
serversItem.port = node.Port;
|
||||
@@ -691,7 +686,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
else
|
||||
{
|
||||
vnextItem = outbound.settings.vnext[0];
|
||||
vnextItem = outbound.settings.vnext.First();
|
||||
}
|
||||
vnextItem.address = node.Address;
|
||||
vnextItem.port = node.Port;
|
||||
@@ -704,7 +699,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
else
|
||||
{
|
||||
usersItem = vnextItem.users[0];
|
||||
usersItem = vnextItem.users.First();
|
||||
}
|
||||
usersItem.id = node.Id;
|
||||
usersItem.email = Global.UserEMail;
|
||||
@@ -712,8 +707,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
|
||||
await GenOutboundMux(node, outbound, _config.CoreBasicItem.MuxEnabled);
|
||||
|
||||
if (node.StreamSecurity == Global.StreamSecurityReality
|
||||
|| node.StreamSecurity == Global.StreamSecurity)
|
||||
if (node.StreamSecurity == Global.StreamSecurityReality || node.StreamSecurity == Global.StreamSecurity)
|
||||
{
|
||||
if (Utils.IsNotEmpty(node.Flow))
|
||||
{
|
||||
@@ -740,7 +734,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
else
|
||||
{
|
||||
serversItem = outbound.settings.servers[0];
|
||||
serversItem = outbound.settings.servers.First();
|
||||
}
|
||||
serversItem.address = node.Address;
|
||||
serversItem.port = node.Port;
|
||||
@@ -757,16 +751,16 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
|
||||
outbound.protocol = Global.ProtocolTypes[node.ConfigType];
|
||||
await GenBoundStreamSettings(node, outbound.streamSettings);
|
||||
await GenBoundStreamSettings(node, outbound);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenOutboundMux(ProfileItem node, Outbounds4Ray outbound, bool enabled)
|
||||
private async Task<int> GenOutboundMux(ProfileItem node, Outbounds4Ray outbound, bool enabled)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -785,19 +779,21 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenBoundStreamSettings(ProfileItem node, StreamSettings4Ray streamSettings)
|
||||
private async Task<int> GenBoundStreamSettings(ProfileItem node, Outbounds4Ray outbound)
|
||||
{
|
||||
try
|
||||
{
|
||||
var streamSettings = outbound.streamSettings;
|
||||
streamSettings.network = node.GetNetwork();
|
||||
string host = node.RequestHost.TrimEx();
|
||||
string sni = node.Sni;
|
||||
string useragent = "";
|
||||
var host = node.RequestHost.TrimEx();
|
||||
var path = node.Path.TrimEx();
|
||||
var sni = node.Sni.TrimEx();
|
||||
var useragent = "";
|
||||
if (!_config.CoreBasicItem.DefUserAgent.IsNullOrEmpty())
|
||||
{
|
||||
try
|
||||
@@ -870,9 +866,9 @@ namespace ServiceLib.Services.CoreConfig
|
||||
{
|
||||
type = node.HeaderType
|
||||
};
|
||||
if (Utils.IsNotEmpty(node.Path))
|
||||
if (Utils.IsNotEmpty(path))
|
||||
{
|
||||
kcpSettings.seed = node.Path;
|
||||
kcpSettings.seed = path;
|
||||
}
|
||||
streamSettings.kcpSettings = kcpSettings;
|
||||
break;
|
||||
@@ -880,9 +876,10 @@ namespace ServiceLib.Services.CoreConfig
|
||||
case nameof(ETransport.ws):
|
||||
WsSettings4Ray wsSettings = new();
|
||||
wsSettings.headers = new Headers4Ray();
|
||||
string path = node.Path;
|
||||
|
||||
if (Utils.IsNotEmpty(host))
|
||||
{
|
||||
wsSettings.host = host;
|
||||
wsSettings.headers.Host = host;
|
||||
}
|
||||
if (Utils.IsNotEmpty(path))
|
||||
@@ -900,9 +897,9 @@ namespace ServiceLib.Services.CoreConfig
|
||||
case nameof(ETransport.httpupgrade):
|
||||
HttpupgradeSettings4Ray httpupgradeSettings = new();
|
||||
|
||||
if (Utils.IsNotEmpty(node.Path))
|
||||
if (Utils.IsNotEmpty(path))
|
||||
{
|
||||
httpupgradeSettings.path = node.Path;
|
||||
httpupgradeSettings.path = path;
|
||||
}
|
||||
if (Utils.IsNotEmpty(host))
|
||||
{
|
||||
@@ -914,16 +911,11 @@ namespace ServiceLib.Services.CoreConfig
|
||||
//xhttp
|
||||
case nameof(ETransport.xhttp):
|
||||
streamSettings.network = ETransport.xhttp.ToString();
|
||||
XhttpSettings4Ray xhttpSettings = new()
|
||||
{
|
||||
scMaxEachPostBytes = "500000-1000000",
|
||||
scMaxConcurrentPosts = "50-100",
|
||||
scMinPostsIntervalMs = "30-50"
|
||||
};
|
||||
XhttpSettings4Ray xhttpSettings = new();
|
||||
|
||||
if (Utils.IsNotEmpty(node.Path))
|
||||
if (Utils.IsNotEmpty(path))
|
||||
{
|
||||
xhttpSettings.path = node.Path;
|
||||
xhttpSettings.path = path;
|
||||
}
|
||||
if (Utils.IsNotEmpty(host))
|
||||
{
|
||||
@@ -939,6 +931,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
|
||||
streamSettings.xhttpSettings = xhttpSettings;
|
||||
await GenOutboundMux(node, outbound, false);
|
||||
|
||||
break;
|
||||
//h2
|
||||
@@ -949,7 +942,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
{
|
||||
httpSettings.host = Utils.String2List(host);
|
||||
}
|
||||
httpSettings.path = node.Path;
|
||||
httpSettings.path = path;
|
||||
|
||||
streamSettings.httpSettings = httpSettings;
|
||||
|
||||
@@ -959,7 +952,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
QuicSettings4Ray quicsettings = new()
|
||||
{
|
||||
security = host,
|
||||
key = node.Path,
|
||||
key = path,
|
||||
header = new Header4Ray
|
||||
{
|
||||
type = node.HeaderType
|
||||
@@ -983,7 +976,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
GrpcSettings4Ray grpcSettings = new()
|
||||
{
|
||||
authority = Utils.IsNullOrEmpty(host) ? null : host,
|
||||
serviceName = node.Path,
|
||||
serviceName = path,
|
||||
multiMode = node.HeaderType == Global.GrpcMultiMode,
|
||||
idle_timeout = _config.GrpcItem.IdleTimeout,
|
||||
health_check_timeout = _config.GrpcItem.HealthCheckTimeout,
|
||||
@@ -1013,9 +1006,9 @@ namespace ServiceLib.Services.CoreConfig
|
||||
request = request.Replace("$requestUserAgent$", $"{useragent.AppendQuotes()}");
|
||||
//Path
|
||||
string pathHttp = @"/";
|
||||
if (Utils.IsNotEmpty(node.Path))
|
||||
if (Utils.IsNotEmpty(path))
|
||||
{
|
||||
string[] arrPath = node.Path.Split(',');
|
||||
string[] arrPath = path.Split(',');
|
||||
pathHttp = string.Join(",".AppendQuotes(), arrPath);
|
||||
}
|
||||
request = request.Replace("$requestPath$", $"{pathHttp.AppendQuotes()}");
|
||||
@@ -1028,12 +1021,12 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenDns(ProfileItem? node, V2rayConfig v2rayConfig)
|
||||
private async Task<int> GenDns(ProfileItem? node, V2rayConfig v2rayConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1091,12 +1084,12 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem)
|
||||
private async Task<int> GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem)
|
||||
{
|
||||
if (node == null)
|
||||
{ return 0; }
|
||||
@@ -1116,7 +1109,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<int> GenStatistic(V2rayConfig v2rayConfig)
|
||||
private async Task<int> GenStatistic(V2rayConfig v2rayConfig)
|
||||
{
|
||||
if (_config.GuiItem.EnableStatistics)
|
||||
{
|
||||
@@ -1167,7 +1160,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
{
|
||||
//fragment proxy
|
||||
if (_config.CoreBasicItem.EnableFragment
|
||||
&& Utils.IsNotEmpty(v2rayConfig.outbounds[0].streamSettings?.security))
|
||||
&& Utils.IsNotEmpty(v2rayConfig.outbounds.First().streamSettings?.security))
|
||||
{
|
||||
var fragmentOutbound = new Outbounds4Ray
|
||||
{
|
||||
@@ -1185,7 +1178,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
};
|
||||
|
||||
v2rayConfig.outbounds.Add(fragmentOutbound);
|
||||
v2rayConfig.outbounds[0].streamSettings.sockopt = new()
|
||||
v2rayConfig.outbounds.First().streamSettings.sockopt = new()
|
||||
{
|
||||
dialerProxy = fragmentOutbound.tag
|
||||
};
|
||||
@@ -1205,7 +1198,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
|
||||
//current proxy
|
||||
var outbound = v2rayConfig.outbounds[0];
|
||||
var outbound = v2rayConfig.outbounds.First();
|
||||
var txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
|
||||
|
||||
//Previous proxy
|
||||
@@ -1249,7 +1242,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace ServiceLib.Services
|
||||
public event EventHandler<RetResult>? UpdateCompleted;
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -68,7 +69,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 +114,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 +132,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 +178,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 +209,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 +233,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;
|
||||
}
|
||||
}
|
||||
@@ -280,13 +281,13 @@ namespace ServiceLib.Services
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.http);
|
||||
if (await SocketCheck(Global.Loopback, httpPort) == false)
|
||||
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||
if (await SocketCheck(Global.Loopback, port) == false)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new WebProxy(Global.Loopback, httpPort);
|
||||
return new WebProxy($"socks5://{Global.Loopback}:{port}");
|
||||
}
|
||||
|
||||
private async Task<bool> SocketCheck(string ip, int port)
|
||||
|
||||
@@ -8,19 +8,17 @@ namespace ServiceLib.Services
|
||||
public class SpeedtestService
|
||||
{
|
||||
private Config? _config;
|
||||
private List<ServerTestItem> _selecteds;
|
||||
private ESpeedActionType _actionType;
|
||||
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)
|
||||
{
|
||||
_config = config;
|
||||
|
||||
_actionType = actionType;
|
||||
_updateFunc = updateFunc;
|
||||
|
||||
_selecteds = new List<ServerTestItem>();
|
||||
var lstSelected = new List<ServerTestItem>();
|
||||
foreach (var it in selecteds)
|
||||
{
|
||||
if (it.ConfigType == EConfigType.Custom)
|
||||
@@ -31,7 +29,7 @@ namespace ServiceLib.Services
|
||||
{
|
||||
continue;
|
||||
}
|
||||
_selecteds.Add(new ServerTestItem()
|
||||
lstSelected.Add(new ServerTestItem()
|
||||
{
|
||||
IndexId = it.IndexId,
|
||||
Address = it.Address,
|
||||
@@ -39,8 +37,9 @@ namespace ServiceLib.Services
|
||||
ConfigType = it.ConfigType
|
||||
});
|
||||
}
|
||||
|
||||
//clear test result
|
||||
foreach (var it in _selecteds)
|
||||
foreach (var it in lstSelected)
|
||||
{
|
||||
switch (actionType)
|
||||
{
|
||||
@@ -63,25 +62,59 @@ namespace ServiceLib.Services
|
||||
}
|
||||
}
|
||||
|
||||
switch (actionType)
|
||||
{
|
||||
case ESpeedActionType.Tcping:
|
||||
Task.Run(RunTcping);
|
||||
break;
|
||||
|
||||
case ESpeedActionType.Realping:
|
||||
Task.Run(RunRealPing);
|
||||
break;
|
||||
|
||||
case ESpeedActionType.Speedtest:
|
||||
Task.Run(RunSpeedTestAsync);
|
||||
break;
|
||||
|
||||
case ESpeedActionType.Mixedtest:
|
||||
Task.Run(RunMixedtestAsync);
|
||||
break;
|
||||
}
|
||||
MessageBus.Current.Listen<string>(EMsgCommand.StopSpeedtest.ToString()).Subscribe(ExitLoop);
|
||||
|
||||
Task.Run(async () => { await RunAsync(actionType, lstSelected); });
|
||||
}
|
||||
|
||||
private async Task RunAsync(ESpeedActionType actionType, List<ServerTestItem> lstSelected)
|
||||
{
|
||||
if (actionType == ESpeedActionType.Tcping)
|
||||
{
|
||||
await RunTcpingAsync(lstSelected);
|
||||
return;
|
||||
}
|
||||
|
||||
var pageSize = _config.SpeedTestItem.SpeedTestPageSize;
|
||||
if (pageSize is <= 0 or > 1000)
|
||||
{
|
||||
pageSize = 1000;
|
||||
}
|
||||
|
||||
List<List<ServerTestItem>> lstTest = new();
|
||||
var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard)).ToList();
|
||||
var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard).ToList();
|
||||
|
||||
for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++)
|
||||
{
|
||||
lstTest.Add(lst1.Skip(num * pageSize).Take(pageSize).ToList());
|
||||
}
|
||||
for (var num = 0; num < (int)Math.Ceiling(lst2.Count * 1.0 / pageSize); num++)
|
||||
{
|
||||
lstTest.Add(lst2.Skip(num * pageSize).Take(pageSize).ToList());
|
||||
}
|
||||
|
||||
foreach (var lst in lstTest)
|
||||
{
|
||||
switch (actionType)
|
||||
{
|
||||
case ESpeedActionType.Realping:
|
||||
await RunRealPingAsync(lst);
|
||||
break;
|
||||
|
||||
case ESpeedActionType.Speedtest:
|
||||
await RunSpeedTestAsync(lst);
|
||||
break;
|
||||
|
||||
case ESpeedActionType.Mixedtest:
|
||||
await RunMixedTestAsync(lst);
|
||||
break;
|
||||
}
|
||||
|
||||
await Task.Delay(100);
|
||||
}
|
||||
|
||||
UpdateFunc("", ResUI.SpeedtestingCompleted);
|
||||
}
|
||||
|
||||
private void ExitLoop(string x)
|
||||
@@ -91,12 +124,12 @@ namespace ServiceLib.Services
|
||||
UpdateFunc("", ResUI.SpeedtestingStop);
|
||||
}
|
||||
|
||||
private async Task RunTcping()
|
||||
private async Task RunTcpingAsync(List<ServerTestItem> selecteds)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<Task> tasks = [];
|
||||
foreach (var it in _selecteds)
|
||||
foreach (var it in selecteds)
|
||||
{
|
||||
if (it.ConfigType == EConfigType.Custom)
|
||||
{
|
||||
@@ -106,7 +139,7 @@ namespace ServiceLib.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
int time = await GetTcpingTime(it.Address, it.Port);
|
||||
var time = await GetTcpingTime(it.Address, it.Port);
|
||||
var output = FormatOut(time, Global.DelayUnit);
|
||||
|
||||
ProfileExHandler.Instance.SetTestDelay(it.IndexId, output);
|
||||
@@ -114,7 +147,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -122,7 +155,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -130,24 +163,22 @@ namespace ServiceLib.Services
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunRealPing()
|
||||
private async Task RunRealPingAsync(List<ServerTestItem> selecteds)
|
||||
{
|
||||
int pid = -1;
|
||||
var pid = -1;
|
||||
try
|
||||
{
|
||||
string msg = string.Empty;
|
||||
|
||||
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(_selecteds);
|
||||
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
|
||||
if (pid < 0)
|
||||
{
|
||||
UpdateFunc("", ResUI.FailedToRunCore);
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadService downloadHandle = new DownloadService();
|
||||
var downloadHandle = new DownloadService();
|
||||
|
||||
List<Task> tasks = new();
|
||||
foreach (var it in _selecteds)
|
||||
foreach (var it in selecteds)
|
||||
{
|
||||
if (!it.AllowTest)
|
||||
{
|
||||
@@ -161,17 +192,17 @@ namespace ServiceLib.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
WebProxy webProxy = new(Global.Loopback, it.Port);
|
||||
string output = await GetRealPingTime(downloadHandle, webProxy);
|
||||
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
|
||||
var output = await GetRealPingTime(downloadHandle, webProxy);
|
||||
|
||||
ProfileExHandler.Instance.SetTestDelay(it.IndexId, output);
|
||||
UpdateFunc(it.IndexId, output);
|
||||
int.TryParse(output, out int delay);
|
||||
int.TryParse(output, out var delay);
|
||||
it.Delay = delay;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -179,39 +210,34 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pid > 0)
|
||||
{
|
||||
CoreHandler.Instance.CoreStopPid(pid);
|
||||
await ProcUtils.ProcessKill(pid);
|
||||
}
|
||||
await ProfileExHandler.Instance.SaveTo();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunSpeedTestAsync()
|
||||
private async Task RunSpeedTestAsync(List<ServerTestItem> selecteds)
|
||||
{
|
||||
int pid = -1;
|
||||
//if (_actionType == ESpeedActionType.Mixedtest)
|
||||
//{
|
||||
// _selecteds = _selecteds.OrderBy(t => t.delay).ToList();
|
||||
//}
|
||||
|
||||
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(_selecteds);
|
||||
var pid = -1;
|
||||
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
|
||||
if (pid < 0)
|
||||
{
|
||||
UpdateFunc("", ResUI.FailedToRunCore);
|
||||
return;
|
||||
}
|
||||
|
||||
string url = _config.SpeedTestItem.SpeedTestUrl;
|
||||
var url = _config.SpeedTestItem.SpeedTestUrl;
|
||||
var timeout = _config.SpeedTestItem.SpeedTestTimeout;
|
||||
|
||||
DownloadService downloadHandle = new();
|
||||
|
||||
foreach (var it in _selecteds)
|
||||
foreach (var it in selecteds)
|
||||
{
|
||||
if (_exitLoop)
|
||||
{
|
||||
@@ -237,11 +263,11 @@ namespace ServiceLib.Services
|
||||
var item = await AppHandler.Instance.GetProfileItem(it.IndexId);
|
||||
if (item is null) continue;
|
||||
|
||||
WebProxy webProxy = new(Global.Loopback, it.Port);
|
||||
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
|
||||
|
||||
await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) =>
|
||||
{
|
||||
decimal.TryParse(msg, out decimal dec);
|
||||
decimal.TryParse(msg, out var dec);
|
||||
if (dec > 0)
|
||||
{
|
||||
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg);
|
||||
@@ -252,28 +278,27 @@ namespace ServiceLib.Services
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
CoreHandler.Instance.CoreStopPid(pid);
|
||||
await ProcUtils.ProcessKill(pid);
|
||||
}
|
||||
UpdateFunc("", ResUI.SpeedtestingCompleted);
|
||||
await ProfileExHandler.Instance.SaveTo();
|
||||
}
|
||||
|
||||
private async Task RunSpeedTestMulti()
|
||||
private async Task RunSpeedTestMulti(List<ServerTestItem> selecteds)
|
||||
{
|
||||
int pid = -1;
|
||||
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(_selecteds);
|
||||
var pid = -1;
|
||||
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
|
||||
if (pid < 0)
|
||||
{
|
||||
UpdateFunc("", ResUI.FailedToRunCore);
|
||||
return;
|
||||
}
|
||||
|
||||
string url = _config.SpeedTestItem.SpeedTestUrl;
|
||||
var url = _config.SpeedTestItem.SpeedTestUrl;
|
||||
var timeout = _config.SpeedTestItem.SpeedTestTimeout;
|
||||
|
||||
DownloadService downloadHandle = new();
|
||||
|
||||
foreach (var it in _selecteds)
|
||||
foreach (var it in selecteds)
|
||||
{
|
||||
if (_exitLoop)
|
||||
{
|
||||
@@ -300,10 +325,10 @@ namespace ServiceLib.Services
|
||||
var item = await AppHandler.Instance.GetProfileItem(it.IndexId);
|
||||
if (item is null) continue;
|
||||
|
||||
WebProxy webProxy = new(Global.Loopback, it.Port);
|
||||
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
|
||||
_ = downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) =>
|
||||
{
|
||||
decimal.TryParse(msg, out decimal dec);
|
||||
decimal.TryParse(msg, out var dec);
|
||||
if (dec > 0)
|
||||
{
|
||||
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg);
|
||||
@@ -317,38 +342,37 @@ namespace ServiceLib.Services
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
CoreHandler.Instance.CoreStopPid(pid);
|
||||
await ProcUtils.ProcessKill(pid);
|
||||
}
|
||||
UpdateFunc("", ResUI.SpeedtestingCompleted);
|
||||
await ProfileExHandler.Instance.SaveTo();
|
||||
}
|
||||
|
||||
private async Task RunMixedtestAsync()
|
||||
private async Task RunMixedTestAsync(List<ServerTestItem> selecteds)
|
||||
{
|
||||
await RunRealPing();
|
||||
await RunRealPingAsync(selecteds);
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
await RunSpeedTestMulti();
|
||||
await RunSpeedTestMulti(selecteds);
|
||||
}
|
||||
|
||||
private async Task<string> GetRealPingTime(DownloadService downloadHandle, IWebProxy webProxy)
|
||||
{
|
||||
int responseTime = await downloadHandle.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
|
||||
var responseTime = await downloadHandle.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
|
||||
//string output = Utile.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status;
|
||||
return FormatOut(responseTime, Global.DelayUnit);
|
||||
}
|
||||
|
||||
private async Task<int> GetTcpingTime(string url, int port)
|
||||
{
|
||||
int responseTime = -1;
|
||||
var responseTime = -1;
|
||||
|
||||
try
|
||||
{
|
||||
if (!IPAddress.TryParse(url, out IPAddress? ipAddress))
|
||||
if (!IPAddress.TryParse(url, out var ipAddress))
|
||||
{
|
||||
IPHostEntry ipHostInfo = Dns.GetHostEntry(url);
|
||||
ipAddress = ipHostInfo.AddressList[0];
|
||||
var ipHostInfo = await Dns.GetHostEntryAsync(url);
|
||||
ipAddress = ipHostInfo.AddressList.First();
|
||||
}
|
||||
|
||||
var timer = Stopwatch.StartNew();
|
||||
@@ -366,7 +390,7 @@ namespace ServiceLib.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return responseTime;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@ namespace ServiceLib.Services.Statistics
|
||||
private Config _config;
|
||||
private bool _exitFlag;
|
||||
private ClientWebSocket? webSocket;
|
||||
private string url = string.Empty;
|
||||
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)
|
||||
{
|
||||
@@ -26,12 +27,10 @@ namespace ServiceLib.Services.Statistics
|
||||
|
||||
try
|
||||
{
|
||||
url = $"ws://{Global.Loopback}:{AppHandler.Instance.StatePort2}/traffic";
|
||||
|
||||
if (webSocket == null)
|
||||
{
|
||||
webSocket = new ClientWebSocket();
|
||||
await webSocket.ConnectAsync(new Uri(url), CancellationToken.None);
|
||||
await webSocket.ConnectAsync(new Uri(Url), CancellationToken.None);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
@@ -50,7 +49,7 @@ namespace ServiceLib.Services.Statistics
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,18 +3,17 @@
|
||||
public class StatisticsXrayService
|
||||
{
|
||||
private const long linkBase = 1024;
|
||||
private string _url;
|
||||
private ServerSpeedItem _serverSpeedItem = new();
|
||||
private Config _config;
|
||||
private bool _exitFlag;
|
||||
private Action<ServerSpeedItem>? _updateFunc;
|
||||
private string Url => $"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort}/debug/vars";
|
||||
|
||||
public StatisticsXrayService(Config config, Action<ServerSpeedItem> updateFunc)
|
||||
{
|
||||
_config = config;
|
||||
_updateFunc = updateFunc;
|
||||
_exitFlag = false;
|
||||
_url = $"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort}/debug/vars";
|
||||
|
||||
Task.Run(Run);
|
||||
}
|
||||
@@ -36,7 +35,7 @@
|
||||
continue;
|
||||
}
|
||||
|
||||
var result = await HttpClientHelper.Instance.TryGetAsync(_url);
|
||||
var result = await HttpClientHelper.Instance.TryGetAsync(Url);
|
||||
if (result != null)
|
||||
{
|
||||
var server = ParseOutput(result) ?? new ServerSpeedItem();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace ServiceLib.ViewModels
|
||||
address = Utils.GetConfigPath(address);
|
||||
if (File.Exists(address))
|
||||
{
|
||||
Utils.ProcessStart(address);
|
||||
ProcUtils.ProcessStart(address);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -160,9 +173,9 @@ namespace ServiceLib.ViewModels
|
||||
var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}");
|
||||
var configDirTemp = Path.Combine(configDirZipTemp, _guiConfigs);
|
||||
|
||||
await Task.Run(() => FileManager.CopyDirectory(configDir, configDirTemp, false, "cache.db"));
|
||||
var ret = await Task.Run(() => FileManager.CreateFromDirectory(configDirZipTemp, fileName));
|
||||
await Task.Run(() => Directory.Delete(configDirZipTemp, true));
|
||||
FileManager.CopyDirectory(configDir, configDirTemp, false, "cache.db");
|
||||
var ret = FileManager.CreateFromDirectory(configDirZipTemp, fileName);
|
||||
Directory.Delete(configDirZipTemp, true);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ namespace ServiceLib.ViewModels
|
||||
FileManager.ZipExtractToFile(fileName, toPath, _config.GuiItem.IgnoreGeoUpdateCore ? "geo" : "");
|
||||
}
|
||||
|
||||
if (Utils.IsLinux() || Utils.IsOSX())
|
||||
if (Utils.IsNonWindows())
|
||||
{
|
||||
var filesList = (new DirectoryInfo(toPath)).GetFiles().Select(u => u.FullName).ToList();
|
||||
foreach (var file in filesList)
|
||||
|
||||
@@ -21,9 +21,6 @@ namespace ServiceLib.ViewModels
|
||||
[Reactive]
|
||||
public string HostFilter { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public int SortingSelected { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool AutoRefresh { get; set; }
|
||||
|
||||
@@ -31,18 +28,12 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
_config = AppHandler.Instance.Config;
|
||||
_updateView = updateView;
|
||||
SortingSelected = _config.ClashUIItem.ConnectionsSorting;
|
||||
AutoRefresh = _config.ClashUIItem.ConnectionsAutoRefresh;
|
||||
|
||||
var canEditRemove = this.WhenAnyValue(
|
||||
x => x.SelectedSource,
|
||||
selectedSource => selectedSource != null && Utils.IsNotEmpty(selectedSource.Id));
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.SortingSelected,
|
||||
y => y >= 0)
|
||||
.Subscribe(async c => await DoSortingSelected(c));
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.AutoRefresh,
|
||||
y => y == true)
|
||||
@@ -84,20 +75,6 @@ namespace ServiceLib.ViewModels
|
||||
});
|
||||
}
|
||||
|
||||
private async Task DoSortingSelected(bool c)
|
||||
{
|
||||
if (!c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (SortingSelected != _config.ClashUIItem.ConnectionsSorting)
|
||||
{
|
||||
_config.ClashUIItem.ConnectionsSorting = SortingSelected;
|
||||
}
|
||||
|
||||
await GetClashConnections();
|
||||
}
|
||||
|
||||
private async Task GetClashConnections()
|
||||
{
|
||||
var ret = await ClashApiHandler.Instance.GetClashConnectionsAsync(_config);
|
||||
@@ -115,7 +92,7 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
var dtNow = DateTime.Now;
|
||||
var lstModel = new List<ClashConnectionModel>();
|
||||
foreach (var item in connections ?? [])
|
||||
foreach (var item in connections ?? new())
|
||||
{
|
||||
var host = $"{(Utils.IsNullOrEmpty(item.metadata.host) ? item.metadata.destinationIP : item.metadata.host)}:{item.metadata.destinationPort}";
|
||||
if (HostFilter.IsNotEmpty() && !host.Contains(HostFilter))
|
||||
@@ -131,45 +108,14 @@ namespace ServiceLib.ViewModels
|
||||
model.Host = host;
|
||||
var sp = (dtNow - item.start);
|
||||
model.Time = sp.TotalSeconds < 0 ? 1 : sp.TotalSeconds;
|
||||
model.Upload = item.upload;
|
||||
model.Download = item.download;
|
||||
model.UploadTraffic = $"{Utils.HumanFy((long)item.upload)}";
|
||||
model.DownloadTraffic = $"{Utils.HumanFy((long)item.download)}";
|
||||
model.Elapsed = sp.ToString(@"hh\:mm\:ss");
|
||||
model.Chain = item.chains?.Count > 0 ? item.chains[0] : string.Empty;
|
||||
item.chains?.Reverse();
|
||||
model.Chain = $"{item.rule} , {string.Join("->", item.chains ?? new())}";
|
||||
|
||||
lstModel.Add(model);
|
||||
}
|
||||
if (lstModel.Count <= 0) { return; }
|
||||
|
||||
//sort
|
||||
switch (SortingSelected)
|
||||
{
|
||||
case 0:
|
||||
lstModel = lstModel.OrderBy(t => t.Upload / t.Time).ToList();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
lstModel = lstModel.OrderBy(t => t.Download / t.Time).ToList();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
lstModel = lstModel.OrderBy(t => t.Upload).ToList();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
lstModel = lstModel.OrderBy(t => t.Download).ToList();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
lstModel = lstModel.OrderBy(t => t.Time).ToList();
|
||||
break;
|
||||
|
||||
case 5:
|
||||
lstModel = lstModel.OrderBy(t => t.Host).ToList();
|
||||
break;
|
||||
}
|
||||
|
||||
_connectionItems.AddRange(lstModel);
|
||||
}
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ namespace ServiceLib.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedGroup = _proxyGroups[0];
|
||||
SelectedGroup = _proxyGroups.First();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -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]
|
||||
@@ -197,6 +197,11 @@ namespace ServiceLib.ViewModels
|
||||
await ApplyRegionalPreset(EPresetType.Russia);
|
||||
});
|
||||
|
||||
RegionalPresetIranCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await ApplyRegionalPreset(EPresetType.Iran);
|
||||
});
|
||||
|
||||
#endregion WhenAnyValue && ReactiveCommand
|
||||
|
||||
Init();
|
||||
@@ -272,9 +277,8 @@ namespace ServiceLib.ViewModels
|
||||
Locator.Current.GetService<ProfilesViewModel>()?.UpdateStatistics(update);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,48 +286,40 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
try
|
||||
{
|
||||
Logging.SaveLog("MyAppExit Begin");
|
||||
//if (blWindowsShutDown)
|
||||
await SysProxyHandler.UpdateSysProxy(_config, true);
|
||||
Logging.SaveLog("MyAppExitAsync Begin");
|
||||
MessageBus.Current.SendMessage("", EMsgCommand.AppExit.ToString());
|
||||
|
||||
await ConfigHandler.SaveConfig(_config);
|
||||
await SysProxyHandler.UpdateSysProxy(_config, true);
|
||||
await ProfileExHandler.Instance.SaveTo();
|
||||
await StatisticsHandler.Instance.SaveTo();
|
||||
StatisticsHandler.Instance.Close();
|
||||
await CoreHandler.Instance.CoreStop();
|
||||
|
||||
Logging.SaveLog("MyAppExit End");
|
||||
Logging.SaveLog("MyAppExitAsync End");
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
_updateView?.Invoke(EViewAction.Shutdown, null);
|
||||
if (!blWindowsShutDown)
|
||||
{
|
||||
_updateView?.Invoke(EViewAction.Shutdown, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -333,6 +329,11 @@ namespace ServiceLib.ViewModels
|
||||
_updateView?.Invoke(EViewAction.ShowHideWindow, blShow);
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
_updateView?.Invoke(EViewAction.Shutdown, null);
|
||||
}
|
||||
|
||||
#endregion Actions
|
||||
|
||||
#region Servers && Groups
|
||||
@@ -501,20 +502,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()
|
||||
@@ -525,17 +514,18 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
private ConcurrentQueue<string> _queueMsg = new();
|
||||
private int _numMaxMsg = 500;
|
||||
private string _lastMsgFilter = string.Empty;
|
||||
private bool _lastMsgFilterNotAvailable;
|
||||
private bool _blLockShow = false;
|
||||
|
||||
@@ -28,7 +27,7 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.MsgFilter)
|
||||
.Subscribe(c => _config.MsgUIItem.MainMsgFilter = MsgFilter);
|
||||
.Subscribe(c => DoMsgFilter());
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.AutoRefresh,
|
||||
@@ -77,8 +76,7 @@ namespace ServiceLib.ViewModels
|
||||
private async Task EnqueueQueueMsg(string msg)
|
||||
{
|
||||
//filter msg
|
||||
if (MsgFilter != _lastMsgFilter) _lastMsgFilterNotAvailable = false;
|
||||
if (Utils.IsNotEmpty(MsgFilter) && !_lastMsgFilterNotAvailable)
|
||||
if (MsgFilter.IsNotEmpty() && !_lastMsgFilterNotAvailable)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -87,12 +85,12 @@ namespace ServiceLib.ViewModels
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
_queueMsg.Enqueue(ex.Message);
|
||||
_lastMsgFilterNotAvailable = true;
|
||||
}
|
||||
}
|
||||
_lastMsgFilter = MsgFilter;
|
||||
|
||||
//Enqueue
|
||||
if (_queueMsg.Count > _numMaxMsg)
|
||||
@@ -113,5 +111,11 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
_queueMsg.Clear();
|
||||
}
|
||||
|
||||
private void DoMsgFilter()
|
||||
{
|
||||
_config.MsgUIItem.MainMsgFilter = MsgFilter;
|
||||
_lastMsgFilterNotAvailable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ namespace ServiceLib.ViewModels
|
||||
#region Core
|
||||
|
||||
[Reactive] public int localPort { get; set; }
|
||||
[Reactive] public bool SecondLocalPortEnabled { get; set; }
|
||||
[Reactive] public bool udpEnabled { get; set; }
|
||||
[Reactive] public bool sniffingEnabled { get; set; }
|
||||
public IList<string> destOverride { get; set; }
|
||||
@@ -62,6 +63,7 @@ namespace ServiceLib.ViewModels
|
||||
[Reactive] public int SpeedTestTimeout { get; set; }
|
||||
[Reactive] public string SpeedTestUrl { get; set; }
|
||||
[Reactive] public string SpeedPingTestUrl { get; set; }
|
||||
[Reactive] public int SpeedTestPageSize { get; set; }
|
||||
[Reactive] public bool EnableHWA { get; set; }
|
||||
[Reactive] public string SubConvertUrl { get; set; }
|
||||
[Reactive] public int MainGirdOrientation { get; set; }
|
||||
@@ -122,8 +124,9 @@ namespace ServiceLib.ViewModels
|
||||
|
||||
#region Core
|
||||
|
||||
var inbound = _config.Inbound[0];
|
||||
var inbound = _config.Inbound.First();
|
||||
localPort = inbound.LocalPort;
|
||||
SecondLocalPortEnabled = inbound.SecondLocalPortEnabled;
|
||||
udpEnabled = inbound.UdpEnabled;
|
||||
sniffingEnabled = inbound.SniffingEnabled;
|
||||
routeOnly = inbound.RouteOnly;
|
||||
@@ -175,6 +178,7 @@ namespace ServiceLib.ViewModels
|
||||
CurrentFontFamily = _config.UiItem.CurrentFontFamily;
|
||||
SpeedTestTimeout = _config.SpeedTestItem.SpeedTestTimeout;
|
||||
SpeedTestUrl = _config.SpeedTestItem.SpeedTestUrl;
|
||||
SpeedTestPageSize = _config.SpeedTestItem.SpeedTestPageSize;
|
||||
SpeedPingTestUrl = _config.SpeedTestItem.SpeedPingTestUrl;
|
||||
EnableHWA = _config.GuiItem.EnableHWA;
|
||||
SubConvertUrl = _config.ConstItem.SubConvertUrl;
|
||||
@@ -285,15 +289,16 @@ namespace ServiceLib.ViewModels
|
||||
//}
|
||||
|
||||
//Core
|
||||
_config.Inbound[0].LocalPort = localPort;
|
||||
_config.Inbound[0].UdpEnabled = udpEnabled;
|
||||
_config.Inbound[0].SniffingEnabled = sniffingEnabled;
|
||||
_config.Inbound[0].DestOverride = destOverride?.ToList();
|
||||
_config.Inbound[0].RouteOnly = routeOnly;
|
||||
_config.Inbound[0].AllowLANConn = allowLANConn;
|
||||
_config.Inbound[0].NewPort4LAN = newPort4LAN;
|
||||
_config.Inbound[0].User = user;
|
||||
_config.Inbound[0].Pass = pass;
|
||||
_config.Inbound.First().LocalPort = localPort;
|
||||
_config.Inbound.First().SecondLocalPortEnabled = SecondLocalPortEnabled;
|
||||
_config.Inbound.First().UdpEnabled = udpEnabled;
|
||||
_config.Inbound.First().SniffingEnabled = sniffingEnabled;
|
||||
_config.Inbound.First().DestOverride = destOverride?.ToList();
|
||||
_config.Inbound.First().RouteOnly = routeOnly;
|
||||
_config.Inbound.First().AllowLANConn = allowLANConn;
|
||||
_config.Inbound.First().NewPort4LAN = newPort4LAN;
|
||||
_config.Inbound.First().User = user;
|
||||
_config.Inbound.First().Pass = pass;
|
||||
if (_config.Inbound.Count > 1)
|
||||
{
|
||||
_config.Inbound.RemoveAt(1);
|
||||
@@ -325,6 +330,7 @@ namespace ServiceLib.ViewModels
|
||||
_config.GuiItem.TrayMenuServersLimit = TrayMenuServersLimit;
|
||||
_config.UiItem.CurrentFontFamily = CurrentFontFamily;
|
||||
_config.SpeedTestItem.SpeedTestTimeout = SpeedTestTimeout;
|
||||
_config.SpeedTestItem.SpeedTestPageSize = SpeedTestPageSize;
|
||||
_config.SpeedTestItem.SpeedTestUrl = SpeedTestUrl;
|
||||
_config.SpeedTestItem.SpeedPingTestUrl = SpeedPingTestUrl;
|
||||
_config.GuiItem.EnableHWA = EnableHWA;
|
||||
@@ -356,6 +362,7 @@ namespace ServiceLib.ViewModels
|
||||
if (await ConfigHandler.SaveConfig(_config) == 0)
|
||||
{
|
||||
await AutoStartupHandler.UpdateTask(_config);
|
||||
AppHandler.Instance.Reset();
|
||||
|
||||
NoticeHandler.Instance.Enqueue(needReboot ? ResUI.NeedRebootTips : ResUI.OperationSuccess);
|
||||
_updateView?.Invoke(EViewAction.CloseWindow, null);
|
||||
|
||||
@@ -374,7 +374,7 @@ namespace ServiceLib.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedProfile = lstModel[0];
|
||||
SelectedProfile = lstModel.First();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,7 +395,7 @@ namespace ServiceLib.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedSub = _subItems[0];
|
||||
SelectedSub = _subItems.First();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,6 +639,7 @@ namespace ServiceLib.ViewModels
|
||||
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
|
||||
|
||||
RefreshServers();
|
||||
SelectedMoveToGroup = null;
|
||||
SelectedMoveToGroup = new();
|
||||
//Reload();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -177,12 +177,12 @@ 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());
|
||||
}
|
||||
|
||||
@@ -451,25 +451,20 @@ namespace ServiceLib.ViewModels
|
||||
public async Task InboundDisplayStatus()
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
sb.Append($"[{EInboundProtocol.socks}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)}]");
|
||||
sb.Append(" | ");
|
||||
sb.Append($"[{EInboundProtocol.http}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.http)}]");
|
||||
sb.Append($"[{EInboundProtocol.mixed}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)}");
|
||||
if (_config.Inbound.First().SecondLocalPortEnabled)
|
||||
{
|
||||
sb.Append($",{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks2)}");
|
||||
}
|
||||
sb.Append(']');
|
||||
InboundDisplay = $"{ResUI.LabLocal}:{sb}";
|
||||
|
||||
if (_config.Inbound[0].AllowLANConn)
|
||||
if (_config.Inbound.First().AllowLANConn)
|
||||
{
|
||||
if (_config.Inbound[0].NewPort4LAN)
|
||||
{
|
||||
StringBuilder sb2 = new();
|
||||
sb2.Append($"[{EInboundProtocol.socks}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks2)}]");
|
||||
sb2.Append(" | ");
|
||||
sb2.Append($"[{EInboundProtocol.http}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.http2)}]");
|
||||
InboundLanDisplay = $"{ResUI.LabLAN}:{sb2}";
|
||||
}
|
||||
else
|
||||
{
|
||||
InboundLanDisplay = $"{ResUI.LabLAN}:{sb}";
|
||||
}
|
||||
var lan = _config.Inbound.First().NewPort4LAN
|
||||
? $"[{EInboundProtocol.mixed}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks3)}]"
|
||||
: $"[{EInboundProtocol.mixed}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)}]";
|
||||
InboundLanDisplay = $"{ResUI.LabLAN}:{lan}";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo 'Building'
|
||||
|
||||
OutputPath='./bin/v2rayN'
|
||||
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o "${OutputPath}/osx-x64"
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o "${OutputPath}/osx-arm64"
|
||||
|
||||
rm -rf "$OutputPath/osx-x64/*.pdb"
|
||||
rm -rf "$OutputPath/osx-arm64/*.pdb"
|
||||
|
||||
echo 'Build done'
|
||||
|
||||
ls $OutputPath
|
||||
7z a v2rayN-osx.zip $OutputPath
|
||||
exit 0
|
||||
@@ -1,62 +0,0 @@
|
||||
param (
|
||||
[Parameter()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$OutputPath = './bin/v2rayN'
|
||||
)
|
||||
|
||||
Write-Host 'Building'
|
||||
|
||||
dotnet publish `
|
||||
./v2rayN/v2rayN.csproj `
|
||||
-c Release `
|
||||
-r win-x64 `
|
||||
--self-contained false `
|
||||
-p:PublishReadyToRun=false `
|
||||
-p:PublishSingleFile=true `
|
||||
-o "$OutputPath/win-x64"
|
||||
|
||||
dotnet publish `
|
||||
./v2rayN/v2rayN.csproj `
|
||||
-c Release `
|
||||
-r win-arm64 `
|
||||
--self-contained false `
|
||||
-p:PublishReadyToRun=false `
|
||||
-p:PublishSingleFile=true `
|
||||
-o "$OutputPath/win-arm64"
|
||||
|
||||
dotnet publish `
|
||||
./v2rayN.Desktop/v2rayN.Desktop.csproj `
|
||||
-c Release `
|
||||
-r linux-x64 `
|
||||
--self-contained true `
|
||||
-p:PublishReadyToRun=false `
|
||||
-p:PublishSingleFile=true `
|
||||
-o "$OutputPath/linux-x64"
|
||||
|
||||
dotnet publish `
|
||||
./v2rayN.Desktop/v2rayN.Desktop.csproj `
|
||||
-c Release `
|
||||
-r linux-arm64 `
|
||||
--self-contained true `
|
||||
-p:PublishReadyToRun=false `
|
||||
-p:PublishSingleFile=true `
|
||||
-o "$OutputPath/linux-arm64"
|
||||
|
||||
|
||||
if ( -Not $? ) {
|
||||
exit $lastExitCode
|
||||
}
|
||||
|
||||
if ( Test-Path -Path ./bin/v2rayN ) {
|
||||
rm -Force "$OutputPath/win-x64/*.pdb"
|
||||
rm -Force "$OutputPath/win-arm64/*.pdb"
|
||||
rm -Force "$OutputPath/linux-x64/*.pdb"
|
||||
rm -Force "$OutputPath/linux-arm64/*.pdb"
|
||||
}
|
||||
|
||||
Write-Host 'Build done'
|
||||
|
||||
ls $OutputPath
|
||||
7z a v2rayN.zip $OutputPath
|
||||
exit 0
|
||||
@@ -56,13 +56,13 @@ public partial class App : Application
|
||||
{
|
||||
}
|
||||
|
||||
private void MenuAddServerViaClipboardClick(object? sender, EventArgs e)
|
||||
private async void MenuAddServerViaClipboardClick(object? sender, EventArgs e)
|
||||
{
|
||||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
if (desktop.MainWindow != null)
|
||||
{
|
||||
var clipboardData = AvaUtils.GetClipboardData(desktop.MainWindow).Result;
|
||||
var clipboardData = await AvaUtils.GetClipboardData(desktop.MainWindow);
|
||||
var service = Locator.Current.GetService<MainWindowViewModel>();
|
||||
if (service != null) _ = service.AddServerViaClipboardAsync(clipboardData);
|
||||
}
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
</Design.PreviewWith>
|
||||
|
||||
<Style Selector="TextBlock.Margin8">
|
||||
<Setter Property="Margin" Value="10" />
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="StackPanel.Margin8">
|
||||
<Setter Property="Margin" Value="10" />
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="DockPanel.Margin8">
|
||||
<Setter Property="Margin" Value="10" />
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="WrapPanel.Margin8">
|
||||
<Setter Property="Margin" Value="10" />
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="Grid.Margin8">
|
||||
<Setter Property="Margin" Value="10" />
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
</Styles>
|
||||
@@ -1,6 +1,5 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Media;
|
||||
using System.Reflection;
|
||||
|
||||
namespace v2rayN.Desktop.Common
|
||||
{
|
||||
@@ -8,7 +7,7 @@ namespace v2rayN.Desktop.Common
|
||||
{
|
||||
public static AppBuilder WithFontByDefault(this AppBuilder appBuilder)
|
||||
{
|
||||
var uri = $"avares://{Assembly.GetExecutingAssembly().GetName().Name}/Assets/Fonts#Noto Sans SC";
|
||||
var uri = Path.Combine(Global.AvaAssets, "Fonts#Noto Sans SC");
|
||||
return appBuilder.With(new FontManagerOptions()
|
||||
{
|
||||
DefaultFamilyName = uri,
|
||||
|
||||
@@ -3,7 +3,6 @@ using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform;
|
||||
using System.Reflection;
|
||||
|
||||
namespace v2rayN.Desktop.Common
|
||||
{
|
||||
@@ -41,7 +40,7 @@ namespace v2rayN.Desktop.Common
|
||||
public static WindowIcon GetAppIcon(ESysProxyType sysProxyType)
|
||||
{
|
||||
var index = (int)sysProxyType + 1;
|
||||
var uri = new Uri($"avares://{Assembly.GetExecutingAssembly().GetName().Name}/Assets/NotifyIcon{index}.ico");
|
||||
var uri = new Uri(Path.Combine(Global.AvaAssets, $"NotifyIcon{index}.ico"));
|
||||
using var bitmap = new Bitmap(AssetLoader.Open(uri));
|
||||
return new(bitmap);
|
||||
}
|
||||
|
||||
@@ -109,7 +109,8 @@ namespace v2rayN.Desktop.ViewModels
|
||||
x.OfType<Menu>(),
|
||||
x.OfType<ContextMenu>(),
|
||||
x.OfType<DataGridRow>(),
|
||||
x.OfType<ListBoxItem>()
|
||||
x.OfType<ListBoxItem>(),
|
||||
x.OfType<HeaderedContentControl>()
|
||||
));
|
||||
style.Add(new Setter()
|
||||
{
|
||||
@@ -137,6 +138,7 @@ namespace v2rayN.Desktop.ViewModels
|
||||
x.OfType<ContextMenu>(),
|
||||
x.OfType<DataGridRow>(),
|
||||
x.OfType<ListBoxItem>(),
|
||||
x.OfType<HeaderedContentControl>(),
|
||||
x.OfType<WindowNotificationManager>()
|
||||
));
|
||||
style.Add(new Setter()
|
||||
|
||||
@@ -34,147 +34,126 @@
|
||||
IsCancel="True" />
|
||||
</StackPanel>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid ColumnDefinitions="Auto,Auto,Auto" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.menuServers}" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.menuServers}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbRemarks}" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbRemarks}" />
|
||||
|
||||
<TextBox
|
||||
x:Name="txtRemarks"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8" />
|
||||
<TextBox
|
||||
x:Name="txtRemarks"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbAddress}" />
|
||||
<TextBox
|
||||
x:Name="txtAddress"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
IsReadOnly="True" />
|
||||
<StackPanel
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnBrowse"
|
||||
Margin="2,0"
|
||||
Content="{x:Static resx:ResUI.TbBrowse}" />
|
||||
<Button
|
||||
x:Name="btnEdit"
|
||||
Margin="2,0"
|
||||
Content="{x:Static resx:ResUI.TbEdit}" />
|
||||
</StackPanel>
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbAddress}" />
|
||||
<TextBox
|
||||
x:Name="txtAddress"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
IsReadOnly="True" />
|
||||
<StackPanel
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnBrowse"
|
||||
Margin="2,0"
|
||||
Content="{x:Static resx:ResUI.TbBrowse}" />
|
||||
<Button
|
||||
x:Name="btnEdit"
|
||||
Margin="2,0"
|
||||
Content="{x:Static resx:ResUI.TbEdit}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbCoreType}" />
|
||||
<ComboBox
|
||||
x:Name="cmbCoreType"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8"
|
||||
MaxDropDownHeight="1000" />
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbCoreType}" />
|
||||
<ComboBox
|
||||
x:Name="cmbCoreType"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8"
|
||||
MaxDropDownHeight="1000" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbDisplayLog}" />
|
||||
<StackPanel
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Classes="Margin8"
|
||||
Orientation="Horizontal">
|
||||
<ToggleSwitch
|
||||
x:Name="togDisplayLog"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TipDisplayLog}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbPreSocksPort}" />
|
||||
<TextBox
|
||||
x:Name="txtPreSocksPort"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbDisplayLog}" />
|
||||
<StackPanel
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Classes="Margin8"
|
||||
Orientation="Horizontal">
|
||||
<ToggleSwitch
|
||||
x:Name="togDisplayLog"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<StackPanel
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Classes="Margin8">
|
||||
<TextBlock
|
||||
Width="500"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TipPreSocksPort}"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
Width="500"
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.CustomServerTips}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TipDisplayLog}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbPreSocksPort}" />
|
||||
<TextBox
|
||||
x:Name="txtPreSocksPort"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<StackPanel
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Classes="Margin8">
|
||||
<TextBlock
|
||||
Width="500"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TipPreSocksPort}"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
Width="500"
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.CustomServerTips}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="{x:Static resx:ResUI.menuServers}"
|
||||
Width="900"
|
||||
Height="700"
|
||||
Height="600"
|
||||
x:DataType="vms:AddServerViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
@@ -34,31 +34,12 @@
|
||||
IsCancel="True" />
|
||||
</StackPanel>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
ColumnDefinitions="180,Auto,Auto"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
@@ -122,18 +103,9 @@
|
||||
<Grid
|
||||
x:Name="gridVMess"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
ColumnDefinitions="180,Auto,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
@@ -184,17 +156,9 @@
|
||||
<Grid
|
||||
x:Name="gridSs"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
ColumnDefinitions="180,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
@@ -225,17 +189,9 @@
|
||||
<Grid
|
||||
x:Name="gridSocks"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
ColumnDefinitions="180,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
@@ -266,18 +222,9 @@
|
||||
<Grid
|
||||
x:Name="gridVLESS"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
ColumnDefinitions="180,Auto,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
@@ -328,17 +275,9 @@
|
||||
<Grid
|
||||
x:Name="gridTrojan"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
ColumnDefinitions="180,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
@@ -369,17 +308,9 @@
|
||||
<Grid
|
||||
x:Name="gridHysteria2"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
ColumnDefinitions="180,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
@@ -410,17 +341,9 @@
|
||||
<Grid
|
||||
x:Name="gridTuic"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
ColumnDefinitions="180,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
@@ -464,19 +387,9 @@
|
||||
<Grid
|
||||
x:Name="gridWireguard"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
ColumnDefinitions="180,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
@@ -551,22 +464,11 @@
|
||||
Grid.Row="3"
|
||||
Margin="0,10" />
|
||||
|
||||
<Grid x:Name="gridTransport" Grid.Row="4">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid
|
||||
x:Name="gridTransport"
|
||||
Grid.Row="4"
|
||||
ColumnDefinitions="180,Auto,Auto"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
@@ -695,18 +597,11 @@
|
||||
|
||||
<Separator Grid.Row="5" Margin="0,10" />
|
||||
|
||||
<Grid x:Name="gridTls" Grid.Row="6">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid
|
||||
x:Name="gridTls"
|
||||
Grid.Row="6"
|
||||
ColumnDefinitions="180,Auto"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
@@ -724,18 +619,9 @@
|
||||
<Grid
|
||||
x:Name="gridTlsMore"
|
||||
Grid.Row="7"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
ColumnDefinitions="180,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
@@ -793,18 +679,9 @@
|
||||
<Grid
|
||||
x:Name="gridRealityMore"
|
||||
Grid.Row="7"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
ColumnDefinitions="180,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
|
||||
@@ -26,20 +26,10 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
ViewModel = new AddServerViewModel(profileItem, UpdateViewHandler);
|
||||
|
||||
if (profileItem.ConfigType == EConfigType.VLESS)
|
||||
Global.CoreTypes.ForEach(it =>
|
||||
{
|
||||
Global.CoreTypes4VLESS.ForEach(it =>
|
||||
{
|
||||
cmbCoreType.Items.Add(it);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.CoreTypes.ForEach(it =>
|
||||
{
|
||||
cmbCoreType.Items.Add(it);
|
||||
});
|
||||
}
|
||||
cmbCoreType.Items.Add(it);
|
||||
});
|
||||
cmbCoreType.Items.Add(string.Empty);
|
||||
|
||||
cmbStreamSecurity.Items.Add(string.Empty);
|
||||
|
||||
@@ -25,17 +25,10 @@
|
||||
VerticalAlignment="Center"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
|
||||
<Grid Classes="Margin8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300" />
|
||||
<ColumnDefinition Width="200" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid
|
||||
Classes="Margin8"
|
||||
ColumnDefinitions="300,200"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
@@ -77,18 +70,10 @@
|
||||
Margin="4"
|
||||
VerticalAlignment="Center"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
<Grid Classes="Margin8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300" />
|
||||
<ColumnDefinition Width="200" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid
|
||||
Classes="Margin8"
|
||||
ColumnDefinitions="300,200"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
@@ -111,18 +96,7 @@
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<StackPanel>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="300" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid ColumnDefinitions="Auto,300" RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
|
||||
@@ -50,24 +50,16 @@
|
||||
<Border
|
||||
Width="500"
|
||||
Height="80"
|
||||
Margin="-2"
|
||||
Margin="-8"
|
||||
VerticalAlignment="Center"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="3*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<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"
|
||||
|
||||
@@ -25,22 +25,6 @@
|
||||
VerticalContentAlignment="Center"
|
||||
Watermark="{x:Static resx:ResUI.ConnectionsHostFilterTitle}" />
|
||||
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSorting}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSorting"
|
||||
Width="100"
|
||||
Margin="8,0">
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingUpSpeed}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDownSpeed}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingUpTraffic}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDownTraffic}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingTime}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingHost}" />
|
||||
</ComboBox>
|
||||
|
||||
<Button
|
||||
x:Name="btnConnectionCloseAll"
|
||||
Width="30"
|
||||
@@ -58,6 +42,23 @@
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
x:Name="btnAutofitColumnWidth"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="8,0"
|
||||
Classes="Success"
|
||||
Theme="{DynamicResource BorderlessButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="20"
|
||||
Height="20"
|
||||
Data="{StaticResource building_fit}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
@@ -85,11 +86,11 @@
|
||||
</DataGrid.ContextMenu>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn
|
||||
Width="240"
|
||||
Width="300"
|
||||
Binding="{Binding Host}"
|
||||
Header="{x:Static resx:ResUI.TbSortingHost}" />
|
||||
<DataGridTextColumn
|
||||
Width="160"
|
||||
Width="500"
|
||||
Binding="{Binding Chain}"
|
||||
Header="{x:Static resx:ResUI.TbSortingChain}" />
|
||||
<DataGridTextColumn
|
||||
@@ -97,17 +98,9 @@
|
||||
Binding="{Binding Network}"
|
||||
Header="{x:Static resx:ResUI.TbSortingNetwork}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Width="160"
|
||||
Binding="{Binding Type}"
|
||||
Header="{x:Static resx:ResUI.TbSortingType}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding UploadTraffic}"
|
||||
Header="{x:Static resx:ResUI.TbSortingUpTraffic}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding DownloadTraffic}"
|
||||
Header="{x:Static resx:ResUI.TbSortingDownTraffic}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding Elapsed}"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Avalonia.Threading;
|
||||
@@ -12,6 +13,7 @@ namespace v2rayN.Desktop.Views
|
||||
{
|
||||
InitializeComponent();
|
||||
ViewModel = new ClashConnectionsViewModel(UpdateViewHandler);
|
||||
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
@@ -22,7 +24,6 @@ namespace v2rayN.Desktop.Views
|
||||
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.menuConnectionCloseAll).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.HostFilter, v => v.txtHostFilter.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SortingSelected, v => v.cmbSorting.SelectedIndex).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.btnConnectionCloseAll).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);
|
||||
});
|
||||
@@ -43,6 +44,19 @@ namespace v2rayN.Desktop.Views
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void BtnAutofitColumnWidth_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
AutofitColumnWidth();
|
||||
}
|
||||
|
||||
private void AutofitColumnWidth()
|
||||
{
|
||||
foreach (var it in lstConnections.Columns)
|
||||
{
|
||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||
}
|
||||
}
|
||||
|
||||
private void btnClose_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel?.ClashConnectionClose(false);
|
||||
|
||||
@@ -105,16 +105,11 @@
|
||||
<DataTemplate>
|
||||
<Border
|
||||
Width="160"
|
||||
Margin="0"
|
||||
Margin="-6"
|
||||
Padding="0"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
<DockPanel>
|
||||
<Grid Grid.Column="0" Classes="Margin8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="8" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Classes="Margin8" RowDefinitions="1*,8,1*">
|
||||
<DockPanel Grid.Row="0">
|
||||
<TextBlock DockPanel.Dock="Right" Text="{Binding Type}" />
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
@@ -143,24 +138,18 @@
|
||||
<DataTemplate>
|
||||
<Border
|
||||
Width="160"
|
||||
Margin="0"
|
||||
Margin="-6"
|
||||
Padding="0"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
<DockPanel>
|
||||
<Border
|
||||
Width="5"
|
||||
Height="30"
|
||||
Margin="0,1"
|
||||
Background="YellowGreen"
|
||||
CornerRadius="4"
|
||||
DockPanel.Dock="Left"
|
||||
IsVisible="{Binding IsActive}" />
|
||||
<Grid Classes="Margin8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="8" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Classes="Margin8" RowDefinitions="1*,8,1*">
|
||||
<TextBlock Grid.Row="0" Text="{Binding Name}" />
|
||||
<DockPanel Grid.Row="2">
|
||||
<TextBlock
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="{x:Static resx:ResUI.menuDNSSetting}"
|
||||
Width="1000"
|
||||
Height="700"
|
||||
Width="900"
|
||||
Height="600"
|
||||
x:DataType="vms:DNSSettingViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
@@ -141,12 +141,7 @@
|
||||
</StackPanel>
|
||||
</WrapPanel>
|
||||
|
||||
<Grid Classes="Margin8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Classes="Margin8" ColumnDefinitions="*,10,*">
|
||||
|
||||
<TextBox
|
||||
x:Name="txtnormalDNS2"
|
||||
|
||||
@@ -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/");
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user