mirror of
https://github.com/2dust/v2rayN.git
synced 2026-05-18 23:54:49 +03:00
Compare commits
351 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b57ba6a98b | |||
| d748e6eff4 | |||
| 315d4b75b2 | |||
| 31267cbc33 | |||
| c23379b3b6 | |||
| 568144d6a2 | |||
| 5857042963 | |||
| 28e41dc621 | |||
| baef3b364b | |||
| 4b9ddb803f | |||
| c07c7ad82f | |||
| e223b80b95 | |||
| 5fe468fa1b | |||
| 60068d8d16 | |||
| b6c5b46afe | |||
| 124cbfadb4 | |||
| 8d21f9b900 | |||
| 398dbbd2e5 | |||
| e9b392d1c0 | |||
| 9d7c7e3225 | |||
| 855fd4f0b7 | |||
| 807839929d | |||
| 870955fee1 | |||
| e0cea929ea | |||
| 315f4c35f0 | |||
| d961ea22a6 | |||
| 5c0c07c78f | |||
| bba93a0fb7 | |||
| 5683df2fc0 | |||
| b5cb9ce67e | |||
| 06a32dc895 | |||
| dff12a8a3a | |||
| dc3f07ee84 | |||
| 1aef49ee11 | |||
| ee3159b00e | |||
| 86d2c307f1 | |||
| 7823a217b4 | |||
| 2004df8337 | |||
| 13bc2d0340 | |||
| edbc850346 | |||
| 901d3c85ca | |||
| abbe83f3c2 | |||
| bb3a04a9c8 | |||
| bac13e8b71 | |||
| 3871681de3 | |||
| ae6f2b6df6 | |||
| f59bbc9981 | |||
| eac0c84e11 | |||
| f814cc443d | |||
| 262466303b | |||
| 3b4cc2c5f2 | |||
| 023d3fbf6f | |||
| fe01f290bc | |||
| 5805ac9f7f | |||
| 4e2f38a343 | |||
| 572c924e5c | |||
| e90353e550 | |||
| f8ae1b8c49 | |||
| 186d995919 | |||
| 70584aff9d | |||
| dcdc63785a | |||
| 0e7bfa65de | |||
| 9427340ab7 | |||
| 63af5bae8a | |||
| 9232f1fa40 | |||
| 15bdb551f4 | |||
| 2cda2b53ed | |||
| 028c9ea0b5 | |||
| 315b51e7ca | |||
| 0185b3b145 | |||
| afaad49879 | |||
| 4b2b45979b | |||
| 66e40edd0e | |||
| 3d5168885f | |||
| 6eee2c2342 | |||
| 11ec27147a | |||
| a522a02ba2 | |||
| 5ff4d35a30 | |||
| 4c5546bf52 | |||
| ab37a46e83 | |||
| 0b3635b5c5 | |||
| 2a338d9a83 | |||
| 7031a4c26c | |||
| 2c5ca97476 | |||
| fc0c8f6bb1 | |||
| 643547704e | |||
| 4717b63775 | |||
| 4af148f480 | |||
| a9c59693ee | |||
| 9b3ac159c1 | |||
| c03c98157f | |||
| 74149b761f | |||
| 44cfa2d8dc | |||
| b0fb00d597 | |||
| af3c1dc039 | |||
| 1c94b5d5f0 | |||
| fbb00c0f85 | |||
| 4a72e63d1c | |||
| ce94e0ba4d | |||
| e2c836794b | |||
| 05e424f805 | |||
| bf30819a4a | |||
| 52e9d30b46 | |||
| 1fa2d55e1d | |||
| 4d0ee652d8 | |||
| ff215bc9aa | |||
| e1cadc878a | |||
| 57d9d8ddb9 | |||
| f76b1a5363 | |||
| 9b579be2be | |||
| 9d43465eab | |||
| fc52870431 | |||
| c466ea100a | |||
| 4054369611 | |||
| 11106937a3 | |||
| fdddf901f3 | |||
| 2e30c04238 | |||
| bd838094cd | |||
| 6f22b74154 | |||
| e71525db0e | |||
| d7c1516ec2 | |||
| ff91a5dad9 | |||
| d76679c2b6 | |||
| d7cb88f0a4 | |||
| 8a3eb41314 | |||
| e2f9aac1c9 | |||
| 08c7396404 | |||
| 69cbdbd20e | |||
| 005f26ba7c | |||
| a1dc0c8104 | |||
| 75435b8fe0 | |||
| 6d7385788e | |||
| 726d9d410f | |||
| ee2a61bb61 | |||
| 40748d6e42 | |||
| 02225ad0b8 | |||
| 3c4703ad85 | |||
| 6762f35ade | |||
| 5135afcf8f | |||
| 4aae82e0cc | |||
| ea95c6de79 | |||
| 4a67e963ed | |||
| 720f177d65 | |||
| 2b4a043a92 | |||
| 77b20bc562 | |||
| 063449448a | |||
| 559ffcbab5 | |||
| 80ed8346be | |||
| a49455f330 | |||
| c3de6f6d02 | |||
| ee416b1bf2 | |||
| 784928ffc8 | |||
| 609360a1d0 | |||
| 18ce2f7b1c | |||
| 78625d82ae | |||
| 2ca34fb9ad | |||
| f5f944aa50 | |||
| 83b4ab83d1 | |||
| 34f63f9006 | |||
| b74188d904 | |||
| ba246e99e8 | |||
| 51576b54c3 | |||
| 0d5a9fcf4a | |||
| b0c5f74edb | |||
| 1ac7661593 | |||
| caa2c523f4 | |||
| 7b9f1e6788 | |||
| 86f3ed29f9 | |||
| 655d411afe | |||
| f5deb8e168 | |||
| fcdb61bfbf | |||
| bd9a4ca094 | |||
| e2657e746d | |||
| 6f5a174231 | |||
| 91e9c0b02b | |||
| 658ea26ab7 | |||
| 77b736541e | |||
| 843b881da6 | |||
| 3ca8acc805 | |||
| 63809d4f16 | |||
| 557660b16b | |||
| 12be8bda52 | |||
| 81efd25e0a | |||
| 7037009ce4 | |||
| 4a0902d4c8 | |||
| ed25ac1748 | |||
| 55e09ed062 | |||
| babb548c22 | |||
| 1d0e8434ad | |||
| e7b2deb941 | |||
| 2a37a6a28e | |||
| 735ebbe92a | |||
| 2031729656 | |||
| f39fdc38cb | |||
| 6b62623615 | |||
| f3f3dc1951 | |||
| f4dd970f5e | |||
| 74332c58c5 | |||
| f7ce49020f | |||
| aaba1f7209 | |||
| a9c7916b3d | |||
| e3c8ccfafe | |||
| 2a22b65b2d | |||
| ce5728e2df | |||
| cba82e0e8e | |||
| be30064f9a | |||
| 1798981380 | |||
| 06586d3405 | |||
| 31bcbd0e13 | |||
| 2652beed88 | |||
| a2b87b862f | |||
| 85e8d9479e | |||
| 119508a4e3 | |||
| 3c2da0a225 | |||
| ef79e6adf9 | |||
| 528400579a | |||
| 521ce1a487 | |||
| 014cc9bc16 | |||
| 34c6c953ac | |||
| 40fbbc7c58 | |||
| 534c329970 | |||
| 328d728257 | |||
| fae6d42758 | |||
| 27693f6d23 | |||
| 89c4bab5b9 | |||
| 9d2ff04838 | |||
| cf00243107 | |||
| e8019ba7a5 | |||
| 4f30e3f0e3 | |||
| 047d08470f | |||
| 9643695389 | |||
| 5cabec86e7 | |||
| f2d0e37255 | |||
| 9560851a3f | |||
| 4aeec1caa1 | |||
| ae45b1ef44 | |||
| aad1b087c9 | |||
| b69c581fa1 | |||
| 9eb4d90cd6 | |||
| 958567c2c5 | |||
| f1fc4583ed | |||
| f7bfd5f766 | |||
| aadc3c216a | |||
| 6fd2499daf | |||
| f0405f1c5d | |||
| 1914cb3994 | |||
| ab38fb572d | |||
| 46d7128a6e | |||
| 0821884ff3 | |||
| 62233281ef | |||
| 39504502af | |||
| f97530a671 | |||
| 0fe7d5e598 | |||
| 527362dc9f | |||
| 1023426c8d | |||
| 4458fd7541 | |||
| f0b03f59ff | |||
| d5b17b3cfb | |||
| 9664d1d77f | |||
| d329646a52 | |||
| 8eafe72bb0 | |||
| c38a0bde65 | |||
| eef5d3cc16 | |||
| 59ada594a5 | |||
| 5ec1d18143 | |||
| fd1e1bb6bf | |||
| 5d545d8a85 | |||
| e38bc45527 | |||
| 1b11425acd | |||
| 1e67850a80 | |||
| 975f89456f | |||
| e267b4b379 | |||
| 2fd21690a5 | |||
| b176ad03aa | |||
| 152c4802d0 | |||
| 8adbc57f23 | |||
| d263a78db8 | |||
| b94a065c06 | |||
| bc957fea71 | |||
| 566f056149 | |||
| abe484b0df | |||
| 982c865245 | |||
| 07d2a27b5f | |||
| e4c65deda8 | |||
| 4930646e05 | |||
| 01dd1ff56f | |||
| 9433213fe5 | |||
| 82dea829f1 | |||
| dafc83aa53 | |||
| 7ab1cd6612 | |||
| d0e3b3ffbd | |||
| 50bcc88700 | |||
| 8fb8575f4b | |||
| e63c113b8a | |||
| 43d892dbf7 | |||
| d9bf31d4f0 | |||
| 0bde282448 | |||
| 6098132fdf | |||
| a6bb8947f3 | |||
| 48880328b0 | |||
| 25776a788e | |||
| f5e8f2831e | |||
| b3fe13c97a | |||
| 7845569319 | |||
| 69b3178c13 | |||
| 1dce0f0366 | |||
| db1b3fdaad | |||
| 032d12a592 | |||
| 94cc36a08f | |||
| 4fcae44fb7 | |||
| 83719dfe17 | |||
| c8b01a5530 | |||
| b469d73385 | |||
| 69468b1770 | |||
| 7e4f66d533 | |||
| 758d0d82d4 | |||
| a01b934fdb | |||
| e9b0372174 | |||
| 288c02e092 | |||
| 33322e8795 | |||
| ec8f6478df | |||
| 59d397a3a0 | |||
| b06540f2ec | |||
| 419f5458b4 | |||
| ca4e8960d2 | |||
| 7b3bed015a | |||
| c97fa3a767 | |||
| 42f7c7cb43 | |||
| c8ae834f50 | |||
| b8644268b3 | |||
| 75742d8a9e | |||
| 6b6169e248 | |||
| 3c4ae902fd | |||
| bfc8bf91ee | |||
| 768d5cce27 | |||
| d54a1c2754 | |||
| 282ad3ab2d | |||
| c692dd3a66 | |||
| e461fce2cb | |||
| 4d92caabf8 | |||
| 07c07ec60a | |||
| 4020213729 | |||
| b9beb4be9d | |||
| f747416d3b | |||
| 41241b694f | |||
| 26c5c1ac01 | |||
| dedd5b197c | |||
| 6340764a6c | |||
| a262c1e98d | |||
| 7b9c64c5a5 | |||
| 4283404f35 |
@@ -0,0 +1,60 @@
|
|||||||
|
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 自动化部署,更新日志应该很快会手动更新
|
||||||
@@ -14,7 +14,8 @@ A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core)
|
|||||||
- Run v2rayN.exe
|
- Run v2rayN.exe
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
- [Microsoft .NET 6.0 Desktop Runtime ](https://download.visualstudio.microsoft.com/download/pr/513d13b7-b456-45af-828b-b7b7981ff462/edf44a743b78f8b54a2cec97ce888346/windowsdesktop-runtime-6.0.15-win-x64.exe)
|
- (6.35 and above)[Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
|
||||||
|
- (6.33 and below)[Microsoft .NET 6.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
|
||||||
- [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
|
- [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+16
-17
@@ -2,7 +2,6 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace PacLib;
|
namespace PacLib;
|
||||||
@@ -50,7 +49,7 @@ public class PacHandler
|
|||||||
_tcpListener = TcpListener.Create(_pacPort);
|
_tcpListener = TcpListener.Create(_pacPort);
|
||||||
_isRunning = true;
|
_isRunning = true;
|
||||||
_tcpListener.Start();
|
_tcpListener.Start();
|
||||||
Task.Factory.StartNew(() =>
|
Task.Factory.StartNew(async () =>
|
||||||
{
|
{
|
||||||
while (_isRunning)
|
while (_isRunning)
|
||||||
{
|
{
|
||||||
@@ -58,25 +57,25 @@ public class PacHandler
|
|||||||
{
|
{
|
||||||
if (!_tcpListener.Pending())
|
if (!_tcpListener.Pending())
|
||||||
{
|
{
|
||||||
Thread.Sleep(10);
|
await Task.Delay(10);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var client = _tcpListener.AcceptTcpClient();
|
var client = _tcpListener.AcceptTcpClient();
|
||||||
Task.Run(() =>
|
await Task.Run(() =>
|
||||||
{
|
{
|
||||||
var stream = client.GetStream();
|
var stream = client.GetStream();
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.AppendLine("HTTP/1.0 200 OK");
|
sb.AppendLine("HTTP/1.0 200 OK");
|
||||||
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
|
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
|
||||||
sb.AppendLine("Connection:close");
|
sb.AppendLine("Connection:close");
|
||||||
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(_pacText));
|
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(_pacText));
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
sb.Append(_pacText);
|
sb.Append(_pacText);
|
||||||
var content = Encoding.UTF8.GetBytes(sb.ToString());
|
var content = Encoding.UTF8.GetBytes(sb.ToString());
|
||||||
stream.Write(content, 0, content.Length);
|
stream.Write(content, 0, content.Length);
|
||||||
stream.Flush();
|
stream.Flush();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -5982,7 +5982,8 @@ var rules = [
|
|||||||
"zyzc9.com",
|
"zyzc9.com",
|
||||||
"zzcartoon.com",
|
"zzcartoon.com",
|
||||||
"zzcloud.me",
|
"zzcloud.me",
|
||||||
"zzux.com"
|
"zzux.com",
|
||||||
|
"chat.openai.com"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
@@ -9,9 +9,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Google.Protobuf" Version="3.22.3" />
|
<PackageReference Include="Google.Protobuf" Version="3.26.1" />
|
||||||
<PackageReference Include="Grpc.Net.Client" Version="2.52.0" />
|
<PackageReference Include="Grpc.Net.Client" Version="2.62.0" />
|
||||||
<PackageReference Include="Grpc.Tools" Version="2.53.0">
|
<PackageReference Include="Grpc.Tools" Version="2.63.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
param (
|
||||||
|
[Parameter()]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[string]
|
||||||
|
$OutputPath = '.\bin\v2rayN'
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-Host 'Building'
|
||||||
|
|
||||||
|
dotnet publish `
|
||||||
|
.\v2rayN\v2rayN.csproj `
|
||||||
|
-c Release `
|
||||||
|
--self-contained false `
|
||||||
|
-p:PublishReadyToRun=true `
|
||||||
|
-p:PublishSingleFile=true `
|
||||||
|
-o $OutputPath
|
||||||
|
|
||||||
|
dotnet publish `
|
||||||
|
.\v2rayUpgrade\v2rayUpgrade.csproj `
|
||||||
|
-c Release `
|
||||||
|
--self-contained false `
|
||||||
|
-p:PublishReadyToRun=true `
|
||||||
|
-p:PublishSingleFile=true `
|
||||||
|
-o $OutputPath
|
||||||
|
|
||||||
|
if ( -Not $? ) {
|
||||||
|
exit $lastExitCode
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( Test-Path -Path .\bin\v2rayN ) {
|
||||||
|
rm -Force "$OutputPath\*.pdb"
|
||||||
|
rm -Force "$OutputPath\*.xml"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host 'Build done'
|
||||||
|
|
||||||
|
ls $OutputPath
|
||||||
|
7z a v2rayN.zip $OutputPath
|
||||||
|
exit 0
|
||||||
+20
-4
@@ -11,15 +11,17 @@
|
|||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<materialDesign:BundledTheme
|
<materialDesign:BundledTheme
|
||||||
BaseTheme="Light"
|
BaseTheme="Light"
|
||||||
PrimaryColor="DeepPurple"
|
PrimaryColor="Blue"
|
||||||
SecondaryColor="Lime" />
|
SecondaryColor="Lime" />
|
||||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign2.Defaults.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
<system:Double x:Key="MenuItemHeight">26</system:Double>
|
<system:Double x:Key="MenuItemHeight">26</system:Double>
|
||||||
<system:Double x:Key="StdFontSize">12</system:Double>
|
<system:Double x:Key="StdFontSize">12</system:Double>
|
||||||
<system:Double x:Key="StdFontSize1">13</system:Double>
|
<system:Double x:Key="StdFontSize1">13</system:Double>
|
||||||
<system:Double x:Key="StdFontSize2">14</system:Double>
|
<system:Double x:Key="StdFontSize2">14</system:Double>
|
||||||
<system:Double x:Key="StdFontSizeMsg">11</system:Double>
|
<system:Double x:Key="StdFontSizeMsg">11</system:Double>
|
||||||
|
|
||||||
|
<conv:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
||||||
<Thickness
|
<Thickness
|
||||||
x:Key="ServerItemMargin"
|
x:Key="ServerItemMargin"
|
||||||
Bottom="4"
|
Bottom="4"
|
||||||
@@ -32,6 +34,12 @@
|
|||||||
Left="8"
|
Left="8"
|
||||||
Right="8"
|
Right="8"
|
||||||
Top="8" />
|
Top="8" />
|
||||||
|
<Thickness
|
||||||
|
x:Key="OutlinedTextBoxDefaultPadding"
|
||||||
|
Bottom="12"
|
||||||
|
Left="16"
|
||||||
|
Right="12"
|
||||||
|
Top="12" />
|
||||||
<Style
|
<Style
|
||||||
x:Key="ModuleTitle"
|
x:Key="ModuleTitle"
|
||||||
BasedOn="{StaticResource MaterialDesignTextBlock}"
|
BasedOn="{StaticResource MaterialDesignTextBlock}"
|
||||||
@@ -64,10 +72,10 @@
|
|||||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<Trigger Property="IsSelected" Value="true">
|
<Trigger Property="IsSelected" Value="true">
|
||||||
<Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}" />
|
<Setter Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
|
||||||
</Trigger>
|
</Trigger>
|
||||||
<Trigger Property="IsMouseOver" Value="true">
|
<Trigger Property="IsMouseOver" Value="true">
|
||||||
<Setter Property="Background" Value="{DynamicResource PrimaryHueMidBrush}" />
|
<Setter Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary}" />
|
||||||
</Trigger>
|
</Trigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
@@ -127,6 +135,7 @@
|
|||||||
BasedOn="{StaticResource MaterialDesignOutlinedTextBox}"
|
BasedOn="{StaticResource MaterialDesignOutlinedTextBox}"
|
||||||
TargetType="{x:Type TextBox}">
|
TargetType="{x:Type TextBox}">
|
||||||
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||||
|
<Setter Property="Padding" Value="{StaticResource OutlinedTextBoxDefaultPadding}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="MyGroupBox"
|
x:Key="MyGroupBox"
|
||||||
@@ -140,6 +149,13 @@
|
|||||||
TargetType="{x:Type ListBoxItem}">
|
TargetType="{x:Type ListBoxItem}">
|
||||||
<Setter Property="Margin" Value="-2,0" />
|
<Setter Property="Margin" Value="-2,0" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style
|
||||||
|
x:Key="MyOutlinedTextComboBox"
|
||||||
|
BasedOn="{StaticResource MaterialDesignOutlinedComboBox}"
|
||||||
|
TargetType="{x:Type ComboBox}">
|
||||||
|
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
|
||||||
|
<Setter Property="Padding" Value="{StaticResource OutlinedTextBoxDefaultPadding}" />
|
||||||
|
</Style>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</Application>
|
||||||
+17
-14
@@ -1,8 +1,8 @@
|
|||||||
using System.Windows;
|
using System.Diagnostics;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using v2rayN.Handler;
|
using v2rayN.Handler;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Models;
|
||||||
using v2rayN.Tool;
|
|
||||||
|
|
||||||
namespace v2rayN
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
@@ -28,24 +28,21 @@ namespace v2rayN
|
|||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
protected override void OnStartup(StartupEventArgs e)
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
{
|
{
|
||||||
Global.ExePathKey = Utils.GetMD5(Utils.GetExePath());
|
var exePathKey = Utils.GetMD5(Utils.GetExePath());
|
||||||
|
|
||||||
var rebootas = (e.Args ?? new string[] { }).Any(t => t == Global.RebootAs);
|
var rebootas = (e.Args ?? new string[] { }).Any(t => t == Global.RebootAs);
|
||||||
ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, Global.ExePathKey, out bool bCreatedNew);
|
ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out bool bCreatedNew);
|
||||||
if (!rebootas && !bCreatedNew)
|
if (!rebootas && !bCreatedNew)
|
||||||
{
|
{
|
||||||
ProgramStarted.Set();
|
ProgramStarted.Set();
|
||||||
Current.Shutdown();
|
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Global.processJob = new Job();
|
|
||||||
|
|
||||||
Logging.Setup();
|
Logging.Setup();
|
||||||
Init();
|
Init();
|
||||||
Logging.LoggingEnabled(_config.guiItem.enableLog);
|
Logging.LoggingEnabled(_config.guiItem.enableLog);
|
||||||
Utils.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
||||||
Logging.ClearLogs();
|
Logging.ClearLogs();
|
||||||
|
|
||||||
Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
|
Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
|
||||||
@@ -57,8 +54,7 @@ namespace v2rayN
|
|||||||
{
|
{
|
||||||
if (ConfigHandler.LoadConfig(ref _config) != 0)
|
if (ConfigHandler.LoadConfig(ref _config) != 0)
|
||||||
{
|
{
|
||||||
UI.ShowWarning($"Loading GUI configuration file is abnormal,please restart the application{Environment.NewLine}加载GUI配置文件异常,请重启应用");
|
UI.Show($"Loading GUI configuration file is abnormal,please restart the application{Environment.NewLine}加载GUI配置文件异常,请重启应用");
|
||||||
Application.Current.Shutdown();
|
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -70,7 +66,7 @@ namespace v2rayN
|
|||||||
|
|
||||||
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("App_DispatcherUnhandledException", e.Exception);
|
Logging.SaveLog("App_DispatcherUnhandledException", e.Exception);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,13 +74,20 @@ namespace v2rayN
|
|||||||
{
|
{
|
||||||
if (e.ExceptionObject != null)
|
if (e.ExceptionObject != null)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject!);
|
Logging.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
|
private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception);
|
Logging.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnExit(ExitEventArgs e)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("OnExit");
|
||||||
|
base.OnExit(e);
|
||||||
|
Process.GetCurrentProcess().Kill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace v2rayN.Base
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
internal class DownloaderHelper
|
internal class DownloaderHelper
|
||||||
{
|
{
|
||||||
@@ -11,14 +11,11 @@ namespace v2rayN.Base
|
|||||||
|
|
||||||
public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
|
public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url))
|
if (Utils.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cancellationToken = new CancellationTokenSource();
|
|
||||||
cancellationToken.CancelAfter(timeout * 1000);
|
|
||||||
|
|
||||||
Uri uri = new(url);
|
Uri uri = new(url);
|
||||||
//Authorization Header
|
//Authorization Header
|
||||||
var headers = new WebHeaderCollection();
|
var headers = new WebHeaderCollection();
|
||||||
@@ -48,7 +45,9 @@ namespace v2rayN.Base
|
|||||||
throw value.Error;
|
throw value.Error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
using var stream = await downloader.DownloadFileTaskAsync(address: url, cancellationToken: cancellationToken.Token);
|
|
||||||
|
using var cts = new CancellationTokenSource();
|
||||||
|
using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
|
||||||
using StreamReader reader = new(stream);
|
using StreamReader reader = new(stream);
|
||||||
|
|
||||||
downloadOpt = null;
|
downloadOpt = null;
|
||||||
@@ -58,14 +57,11 @@ namespace v2rayN.Base
|
|||||||
|
|
||||||
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
|
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url))
|
if (Utils.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(url));
|
throw new ArgumentNullException(nameof(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
var cancellationToken = new CancellationTokenSource();
|
|
||||||
cancellationToken.CancelAfter(timeout * 1000);
|
|
||||||
|
|
||||||
var downloadOpt = new DownloadConfiguration()
|
var downloadOpt = new DownloadConfiguration()
|
||||||
{
|
{
|
||||||
Timeout = timeout * 1000,
|
Timeout = timeout * 1000,
|
||||||
@@ -115,19 +111,20 @@ namespace v2rayN.Base
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
//progress.Report("......");
|
//progress.Report("......");
|
||||||
|
using var cts = new CancellationTokenSource();
|
||||||
using var stream = await downloader.DownloadFileTaskAsync(address: url, cancellationToken: cancellationToken.Token);
|
cts.CancelAfter(timeout * 1000);
|
||||||
|
using var stream = await downloader.DownloadFileTaskAsync(address: url, cts.Token);
|
||||||
|
|
||||||
downloadOpt = null;
|
downloadOpt = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress<double> progress, int timeout)
|
public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress<double> progress, int timeout)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url))
|
if (Utils.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(url));
|
throw new ArgumentNullException(nameof(url));
|
||||||
}
|
}
|
||||||
if (string.IsNullOrEmpty(fileName))
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(fileName));
|
throw new ArgumentNullException(nameof(fileName));
|
||||||
}
|
}
|
||||||
@@ -136,9 +133,6 @@ namespace v2rayN.Base
|
|||||||
File.Delete(fileName);
|
File.Delete(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
var cancellationToken = new CancellationTokenSource();
|
|
||||||
cancellationToken.CancelAfter(timeout * 1000);
|
|
||||||
|
|
||||||
var downloadOpt = new DownloadConfiguration()
|
var downloadOpt = new DownloadConfiguration()
|
||||||
{
|
{
|
||||||
Timeout = timeout * 1000,
|
Timeout = timeout * 1000,
|
||||||
@@ -178,7 +172,8 @@ namespace v2rayN.Base
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
await downloader.DownloadFileTaskAsync(url, fileName, cancellationToken: cancellationToken.Token);
|
using var cts = new CancellationTokenSource();
|
||||||
|
await downloader.DownloadFileTaskAsync(url, fileName, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
|
||||||
|
|
||||||
downloadOpt = null;
|
downloadOpt = null;
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace v2rayN.Tool
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
public static class FileManager
|
public static class FileManager
|
||||||
{
|
{
|
||||||
@@ -15,12 +15,12 @@ namespace v2rayN.Tool
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UncompressFile(string fileName, byte[] content)
|
public static void UncompressedFile(string fileName, byte[] content)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -30,7 +30,7 @@ namespace v2rayN.Tool
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ namespace v2rayN.Tool
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,13 +75,13 @@ namespace v2rayN.Tool
|
|||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -3,7 +3,7 @@ using System.Net.Http;
|
|||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace v2rayN.Base
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -23,19 +23,19 @@ namespace v2rayN.Base
|
|||||||
|
|
||||||
public async Task<string?> GetAsync(string url)
|
public async Task<string?> GetAsync(string url)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url)) return null;
|
if (Utils.IsNullOrEmpty(url)) return null;
|
||||||
return await httpClient.GetStringAsync(url);
|
return await httpClient.GetStringAsync(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
|
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(url)) return null;
|
if (Utils.IsNullOrEmpty(url)) return null;
|
||||||
return await client.GetStringAsync(url, token);
|
return await client.GetStringAsync(url, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PutAsync(string url, Dictionary<string, string> headers)
|
public async Task PutAsync(string url, Dictionary<string, string> headers)
|
||||||
{
|
{
|
||||||
var jsonContent = Utils.ToJson(headers);
|
var jsonContent = JsonUtils.Serialize(headers);
|
||||||
var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
|
var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
|
||||||
|
|
||||||
var result = await httpClient.PutAsync(url, content);
|
var result = await httpClient.PutAsync(url, content);
|
||||||
@@ -76,19 +76,19 @@ namespace v2rayN.Base
|
|||||||
//if (progressPercentage != percent && percent % 10 == 0)
|
//if (progressPercentage != percent && percent % 10 == 0)
|
||||||
{
|
{
|
||||||
progressPercentage = percent;
|
progressPercentage = percent;
|
||||||
progress!.Report(percent);
|
progress?.Report(percent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (canReportProgress)
|
if (canReportProgress)
|
||||||
{
|
{
|
||||||
progress!.Report(101);
|
progress?.Report(101);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default)
|
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(url))
|
if (Utils.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(url));
|
throw new ArgumentNullException(nameof(url));
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,6 @@ namespace v2rayN.Base
|
|||||||
var data = new byte[read];
|
var data = new byte[read];
|
||||||
buffer.ToList().CopyTo(0, data, 0, read);
|
buffer.ToList().CopyTo(0, data, 0, read);
|
||||||
|
|
||||||
// TODO:
|
|
||||||
totalRead += read;
|
totalRead += read;
|
||||||
|
|
||||||
TimeSpan ts = (DateTime.Now - totalDatetime);
|
TimeSpan ts = (DateTime.Now - totalDatetime);
|
||||||
@@ -52,7 +52,7 @@ namespace v2rayN
|
|||||||
|
|
||||||
if (!succ)
|
if (!succ)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error());
|
Logging.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error());
|
||||||
}
|
}
|
||||||
|
|
||||||
return succ;
|
return succ;
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace v2rayN
|
||||||
|
{
|
||||||
|
internal class JsonUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// DeepCopy
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T DeepCopy<T>(T obj)
|
||||||
|
{
|
||||||
|
return Deserialize<T>(Serialize(obj, false))!;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deserialize to object
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="strJson"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T? Deserialize<T>(string? strJson)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(strJson))
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
return JsonSerializer.Deserialize<T>(strJson);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// parse
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="strJson"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static JsonNode? ParseJson(string strJson)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(strJson))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return JsonNode.Parse(strJson);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//SaveLog(ex.Message, ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serialize Object to Json string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <param name="indented"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Serialize(object? obj, bool indented = true)
|
||||||
|
{
|
||||||
|
string result = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
var options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = indented ? true : false,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||||
|
};
|
||||||
|
result = JsonSerializer.Serialize(obj, options);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SerializeToNode
|
||||||
|
/// </summary>
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using FileStream file = File.Create(filePath);
|
||||||
|
|
||||||
|
var options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
|
||||||
|
};
|
||||||
|
|
||||||
|
JsonSerializer.Serialize(file, obj, options);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ using NLog.Config;
|
|||||||
using NLog.Targets;
|
using NLog.Targets;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace v2rayN.Tool
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
public class Logging
|
public class Logging
|
||||||
{
|
{
|
||||||
@@ -51,5 +51,28 @@ namespace v2rayN.Tool
|
|||||||
catch { }
|
catch { }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SaveLog(string strContent)
|
||||||
|
{
|
||||||
|
if (LogManager.IsLoggingEnabled())
|
||||||
|
{
|
||||||
|
var logger = LogManager.GetLogger("Log1");
|
||||||
|
logger.Info(strContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SaveLog(string strTitle, Exception ex)
|
||||||
|
{
|
||||||
|
if (LogManager.IsLoggingEnabled())
|
||||||
|
{
|
||||||
|
var logger = LogManager.GetLogger("Log2");
|
||||||
|
logger.Debug($"{strTitle},{ex.Message}");
|
||||||
|
logger.Debug(ex.StackTrace);
|
||||||
|
if (ex?.InnerException != null)
|
||||||
|
{
|
||||||
|
logger.Error(ex.InnerException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
using QRCoder;
|
||||||
|
using QRCoder.Xaml;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using ZXing.Common;
|
||||||
|
using ZXing.QrCode;
|
||||||
|
using ZXing.Windows.Compatibility;
|
||||||
|
using ZXing;
|
||||||
|
|
||||||
|
namespace v2rayN
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 含有QR码的描述类和包装编码和渲染
|
||||||
|
/// </summary>
|
||||||
|
public class QRCodeHelper
|
||||||
|
{
|
||||||
|
public static DrawingImage? GetQRCode(string? strContent)
|
||||||
|
{
|
||||||
|
if (strContent is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QRCodeGenerator qrGenerator = new();
|
||||||
|
QRCodeData qrCodeData = qrGenerator.CreateQrCode(strContent, QRCodeGenerator.ECCLevel.H);
|
||||||
|
XamlQRCode qrCode = new(qrCodeData);
|
||||||
|
DrawingImage qrCodeAsXaml = qrCode.GetGraphic(40);
|
||||||
|
return qrCodeAsXaml;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ScanScreen(float dpiX, float dpiY)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var left = (int)(SystemParameters.WorkArea.Left);
|
||||||
|
var top = (int)(SystemParameters.WorkArea.Top);
|
||||||
|
var width = (int)(SystemParameters.WorkArea.Width / dpiX);
|
||||||
|
var height = (int)(SystemParameters.WorkArea.Height / dpiY);
|
||||||
|
|
||||||
|
using Bitmap fullImage = new Bitmap(width, height);
|
||||||
|
using (Graphics g = Graphics.FromImage(fullImage))
|
||||||
|
{
|
||||||
|
g.CopyFromScreen(left, top, 0, 0, fullImage.Size, CopyPixelOperation.SourceCopy);
|
||||||
|
}
|
||||||
|
int maxTry = 10;
|
||||||
|
for (int i = 0; i < maxTry; i++)
|
||||||
|
{
|
||||||
|
int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry);
|
||||||
|
int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry);
|
||||||
|
Rectangle cropRect = new(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
|
||||||
|
Bitmap target = new(width, height);
|
||||||
|
|
||||||
|
double imageScale = (double)width / (double)cropRect.Width;
|
||||||
|
using (Graphics g = Graphics.FromImage(target))
|
||||||
|
{
|
||||||
|
g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height),
|
||||||
|
cropRect,
|
||||||
|
GraphicsUnit.Pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
BitmapLuminanceSource source = new(target);
|
||||||
|
QRCodeReader reader = new();
|
||||||
|
|
||||||
|
BinaryBitmap bitmap = new(new HybridBinarizer(source));
|
||||||
|
var result = reader.decode(bitmap);
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return result.Text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BinaryBitmap bitmap2 = new(new HybridBinarizer(source.invert()));
|
||||||
|
var result2 = reader.decode(bitmap2);
|
||||||
|
if (result2 != null)
|
||||||
|
{
|
||||||
|
return result2.Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tuple<float, float> GetDpiXY(Window window)
|
||||||
|
{
|
||||||
|
IntPtr hWnd = new WindowInteropHelper(window).EnsureHandle();
|
||||||
|
Graphics g = Graphics.FromHwnd(hWnd);
|
||||||
|
|
||||||
|
return new(96 / g.DpiX, 96 / g.DpiY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-6
@@ -1,7 +1,7 @@
|
|||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace v2rayN.Tool
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
public static class QueryableExtension
|
public static class QueryableExtension
|
||||||
{
|
{
|
||||||
@@ -29,22 +29,22 @@ namespace v2rayN.Tool
|
|||||||
|
|
||||||
public static IOrderedQueryable<T> OrderByInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
|
public static IOrderedQueryable<T> OrderByInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
|
||||||
{//public
|
{//public
|
||||||
return query.OrderBy(_GetLamba<T, TProp>(memberProperty));
|
return query.OrderBy(_GetLambda<T, TProp>(memberProperty));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IOrderedQueryable<T> OrderByDescendingInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
|
public static IOrderedQueryable<T> OrderByDescendingInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
|
||||||
{//public
|
{//public
|
||||||
return query.OrderByDescending(_GetLamba<T, TProp>(memberProperty));
|
return query.OrderByDescending(_GetLambda<T, TProp>(memberProperty));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Expression<Func<T, TProp>> _GetLamba<T, TProp>(PropertyInfo memberProperty)
|
private static Expression<Func<T, TProp>> _GetLambda<T, TProp>(PropertyInfo memberProperty)
|
||||||
{
|
{
|
||||||
if (memberProperty.PropertyType != typeof(TProp)) throw new Exception();
|
if (memberProperty.PropertyType != typeof(TProp)) throw new Exception();
|
||||||
|
|
||||||
var thisArg = Expression.Parameter(typeof(T));
|
var thisArg = Expression.Parameter(typeof(T));
|
||||||
var lamba = Expression.Lambda<Func<T, TProp>>(Expression.Property(thisArg, memberProperty), thisArg);
|
var lambda = Expression.Lambda<Func<T, TProp>>(Expression.Property(thisArg, memberProperty), thisArg);
|
||||||
|
|
||||||
return lamba;
|
return lambda;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
namespace v2rayN
|
||||||
|
{
|
||||||
|
public class SemanticVersion
|
||||||
|
{
|
||||||
|
private int major;
|
||||||
|
private int minor;
|
||||||
|
private int patch;
|
||||||
|
private string version;
|
||||||
|
|
||||||
|
public SemanticVersion(int major, int minor, int patch)
|
||||||
|
{
|
||||||
|
this.major = major;
|
||||||
|
this.minor = minor;
|
||||||
|
this.patch = patch;
|
||||||
|
this.version = $"{major}.{minor}.{patch}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public SemanticVersion(string version)
|
||||||
|
{
|
||||||
|
this.version = version.RemovePrefix('v');
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string[] parts = this.version.Split('.');
|
||||||
|
if (parts.Length == 2)
|
||||||
|
{
|
||||||
|
this.major = int.Parse(parts[0]);
|
||||||
|
this.minor = int.Parse(parts[1]);
|
||||||
|
this.patch = 0;
|
||||||
|
}
|
||||||
|
else if (parts.Length == 3)
|
||||||
|
{
|
||||||
|
this.major = int.Parse(parts[0]);
|
||||||
|
this.minor = int.Parse(parts[1]);
|
||||||
|
this.patch = int.Parse(parts[2]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Invalid version string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
this.major = 0;
|
||||||
|
this.minor = 0;
|
||||||
|
this.patch = 0;
|
||||||
|
//this.version = "0.0.0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (obj is SemanticVersion other)
|
||||||
|
{
|
||||||
|
return this.major == other.major && this.minor == other.minor && this.patch == other.patch;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return this.major.GetHashCode() ^ this.minor.GetHashCode() ^ this.patch.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Use ToVersionString(string? prefix) instead if possible.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>major.minor.patch</returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return this.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToVersionString(string? prefix = null)
|
||||||
|
{
|
||||||
|
if (prefix == null)
|
||||||
|
{
|
||||||
|
return this.version;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $"{prefix}{this.version}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(SemanticVersion v1, SemanticVersion v2)
|
||||||
|
{ return v1.Equals(v2); }
|
||||||
|
|
||||||
|
public static bool operator !=(SemanticVersion v1, SemanticVersion v2)
|
||||||
|
{ return !v1.Equals(v2); }
|
||||||
|
|
||||||
|
public static bool operator >=(SemanticVersion v1, SemanticVersion v2)
|
||||||
|
{ return v1.GreaterEquals(v2); }
|
||||||
|
|
||||||
|
public static bool operator <=(SemanticVersion v1, SemanticVersion v2)
|
||||||
|
{ return v1.LessEquals(v2); }
|
||||||
|
|
||||||
|
#region Private
|
||||||
|
|
||||||
|
private bool GreaterEquals(SemanticVersion other)
|
||||||
|
{
|
||||||
|
if (this.major < other.major)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (this.major > other.major)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this.minor < other.minor)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (this.minor > other.minor)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this.patch < other.patch)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (this.patch > other.patch)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool LessEquals(SemanticVersion other)
|
||||||
|
{
|
||||||
|
if (this.major < other.major)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (this.major > other.major)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this.minor < other.minor)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (this.minor > other.minor)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this.patch < other.patch)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (this.patch > other.patch)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Private
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,21 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
namespace v2rayN.Base
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
public sealed class SqliteHelper
|
public sealed class SQLiteHelper
|
||||||
{
|
{
|
||||||
private static readonly Lazy<SqliteHelper> _instance = new(() => new());
|
private static readonly Lazy<SQLiteHelper> _instance = new(() => new());
|
||||||
public static SqliteHelper Instance => _instance.Value;
|
public static SQLiteHelper Instance => _instance.Value;
|
||||||
private string _connstr;
|
private string _connstr;
|
||||||
private SQLiteConnection _db;
|
private SQLiteConnection _db;
|
||||||
private SQLiteAsyncConnection _dbAsync;
|
private SQLiteAsyncConnection _dbAsync;
|
||||||
private static readonly object objLock = new();
|
private static readonly object objLock = new();
|
||||||
|
public readonly string _configDB = "guiNDB.db";
|
||||||
|
|
||||||
public SqliteHelper()
|
public SQLiteHelper()
|
||||||
{
|
{
|
||||||
_connstr = Utils.GetConfigPath(Global.ConfigDB);
|
_connstr = Utils.GetConfigPath(_configDB);
|
||||||
_db = new SQLiteConnection(_connstr, false);
|
_db = new SQLiteConnection(_connstr, false);
|
||||||
_dbAsync = new SQLiteAsyncConnection(_connstr, false);
|
_dbAsync = new SQLiteAsyncConnection(_connstr, false);
|
||||||
}
|
}
|
||||||
@@ -50,7 +51,7 @@ namespace v2rayN.Base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> Replacesync(object model)
|
public async Task<int> ReplaceAsync(object model)
|
||||||
{
|
{
|
||||||
return await _dbAsync.InsertOrReplaceAsync(model);
|
return await _dbAsync.InsertOrReplaceAsync(model);
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace v2rayN.Base
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
internal static class StringEx
|
internal static class StringEx
|
||||||
{
|
{
|
||||||
@@ -46,5 +46,49 @@ namespace v2rayN.Base
|
|||||||
{
|
{
|
||||||
return value == null ? string.Empty : value.Trim();
|
return value == null ? string.Empty : value.Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string RemovePrefix(this string value, char prefix)
|
||||||
|
{
|
||||||
|
if (value.StartsWith(prefix))
|
||||||
|
{
|
||||||
|
return value.Substring(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string RemovePrefix(this string value, string prefix)
|
||||||
|
{
|
||||||
|
if (value.StartsWith(prefix))
|
||||||
|
{
|
||||||
|
return value.Substring(prefix.Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string UpperFirstChar(this string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return char.ToUpper(value[0]) + value.Substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string AppendQuotes(this string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"\"{value}\"";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Windows;
|
using Microsoft.Win32;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
namespace v2rayN
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
@@ -11,14 +12,28 @@ namespace v2rayN
|
|||||||
MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
|
MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ShowWarning(string msg)
|
|
||||||
{
|
|
||||||
MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Warning, MessageBoxResult.OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MessageBoxResult ShowYesNo(string msg)
|
public static MessageBoxResult ShowYesNo(string msg)
|
||||||
{
|
{
|
||||||
return MessageBox.Show(msg, caption, MessageBoxButton.YesNo, MessageBoxImage.Question);
|
return MessageBox.Show(msg, caption, MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool? OpenFileDialog(out string fileName, string filter)
|
||||||
|
{
|
||||||
|
fileName = string.Empty;
|
||||||
|
|
||||||
|
var fileDialog = new OpenFileDialog
|
||||||
|
{
|
||||||
|
Multiselect = false,
|
||||||
|
Filter = filter
|
||||||
|
};
|
||||||
|
|
||||||
|
if (fileDialog.ShowDialog() != true)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fileName = fileDialog.FileName;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace v2rayN.Converters
|
||||||
|
{
|
||||||
|
[ValueConversion(typeof(bool), typeof(bool))]
|
||||||
|
public class InverseBooleanConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (targetType != typeof(bool))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("The target must be a boolean");
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(bool)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ namespace v2rayN.Converters
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var fontFamily = LazyConfig.Instance.GetConfig().uiItem.currentFontFamily;
|
var fontFamily = LazyConfig.Instance.GetConfig().uiItem.currentFontFamily;
|
||||||
if (!string.IsNullOrEmpty(fontFamily))
|
if (!Utils.IsNullOrEmpty(fontFamily))
|
||||||
{
|
{
|
||||||
var fontPath = Utils.GetFontsPath();
|
var fontPath = Utils.GetFontsPath();
|
||||||
MyFont = new FontFamily(new Uri(@$"file:///{fontPath}\"), $"./#{fontFamily}");
|
MyFont = new FontFamily(new Uri(@$"file:///{fontPath}\"), $"./#{fontFamily}");
|
||||||
|
|||||||
+104
-80
@@ -1,83 +1,75 @@
|
|||||||
namespace v2rayN
|
using v2rayN.Models;
|
||||||
|
|
||||||
|
namespace v2rayN
|
||||||
{
|
{
|
||||||
internal class Global
|
internal class Global
|
||||||
{
|
{
|
||||||
#region const
|
#region const
|
||||||
|
|
||||||
public const string githubUrl = "https://github.com";
|
public const string GithubUrl = "https://github.com";
|
||||||
public const string githubApiUrl = "https://api.github.com/repos";
|
public const string GithubApiUrl = "https://api.github.com/repos";
|
||||||
public const string v2rayWebsiteUrl = @"https://www.v2fly.org/";
|
public const string V2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases";
|
||||||
public const string AboutUrl = @"https://github.com/2dust/v2rayN";
|
public const string XrayCoreUrl = "https://github.com/XTLS/Xray-core/releases";
|
||||||
public const string UpdateUrl = AboutUrl + @"/releases";
|
|
||||||
public const string v2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases";
|
|
||||||
public const string xrayCoreUrl = "https://github.com/XTLS/Xray-core/releases";
|
|
||||||
public const string SagerNetCoreUrl = "https://github.com/SagerNet/v2ray-core/releases";
|
public const string SagerNetCoreUrl = "https://github.com/SagerNet/v2ray-core/releases";
|
||||||
public const string NUrl = @"https://github.com/2dust/v2rayN/releases";
|
public const string NUrl = @"https://github.com/2dust/v2rayN/releases";
|
||||||
public const string clashCoreUrl = "https://github.com/Dreamacro/clash/releases";
|
public const string ClashCoreUrl = "https://github.com/Dreamacro/clash/releases";
|
||||||
public const string clashMetaCoreUrl = "https://github.com/MetaCubeX/Clash.Meta/releases";
|
public const string ClashMetaCoreUrl = "https://github.com/MetaCubeX/Clash.Meta/releases";
|
||||||
public const string hysteriaCoreUrl = "https://github.com/apernet/hysteria/releases";
|
public const string MihomoCoreUrl = "https://github.com/MetaCubeX/mihomo/releases";
|
||||||
public const string naiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
|
public const string HysteriaCoreUrl = "https://github.com/apernet/hysteria/releases";
|
||||||
public const string tuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
|
public const string NaiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
|
||||||
public const string singboxCoreUrl = "https://github.com/SagerNet/sing-box/releases";
|
public const string TuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
|
||||||
public const string geoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
|
public const string SingboxCoreUrl = "https://github.com/SagerNet/sing-box/releases";
|
||||||
|
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
|
||||||
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
||||||
|
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
|
||||||
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
||||||
|
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/SagerNet/sing-{0}/rule-set/{1}.srs";
|
||||||
|
|
||||||
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
||||||
public const string ConfigFileName = "guiNConfig.json";
|
public const string ConfigFileName = "guiNConfig.json";
|
||||||
public const string ConfigDB = "guiNDB.db";
|
public const string CoreConfigFileName = "config.json";
|
||||||
public const string coreConfigFileName = "config.json";
|
public const string CorePreConfigFileName = "configPre.json";
|
||||||
public const string v2raySampleClient = "v2rayN.Sample.SampleClientConfig";
|
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
|
||||||
public const string v2raySampleServer = "v2rayN.Sample.SampleServerConfig";
|
public const string V2raySampleClient = "v2rayN.Sample.SampleClientConfig";
|
||||||
public const string v2raySampleHttprequestFileName = "v2rayN.Sample.SampleHttprequest";
|
public const string SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig";
|
||||||
public const string v2raySampleHttpresponseFileName = "v2rayN.Sample.SampleHttpresponse";
|
public const string V2raySampleHttpRequestFileName = "v2rayN.Sample.SampleHttpRequest";
|
||||||
|
public const string V2raySampleHttpResponseFileName = "v2rayN.Sample.SampleHttpResponse";
|
||||||
|
public const string V2raySampleInbound = "v2rayN.Sample.SampleInbound";
|
||||||
|
public const string V2raySampleOutbound = "v2rayN.Sample.SampleOutbound";
|
||||||
|
public const string SingboxSampleOutbound = "v2rayN.Sample.SingboxSampleOutbound";
|
||||||
public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_";
|
public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_";
|
||||||
public const string v2raySampleInbound = "v2rayN.Sample.SampleInbound";
|
|
||||||
public const string TunSingboxFileName = "v2rayN.Sample.tun_singbox";
|
|
||||||
public const string TunSingboxDNSFileName = "v2rayN.Sample.tun_singbox_dns";
|
public const string TunSingboxDNSFileName = "v2rayN.Sample.tun_singbox_dns";
|
||||||
|
public const string TunSingboxInboundFileName = "v2rayN.Sample.tun_singbox_inbound";
|
||||||
|
public const string TunSingboxRulesFileName = "v2rayN.Sample.tun_singbox_rules";
|
||||||
|
public const string DNSV2rayNormalFileName = "v2rayN.Sample.dns_v2ray_normal";
|
||||||
|
public const string DNSSingboxNormalFileName = "v2rayN.Sample.dns_singbox_normal";
|
||||||
|
|
||||||
public const string DefaultSecurity = "auto";
|
public const string DefaultSecurity = "auto";
|
||||||
public const string DefaultNetwork = "tcp";
|
public const string DefaultNetwork = "tcp";
|
||||||
public const string TcpHeaderHttp = "http";
|
public const string TcpHeaderHttp = "http";
|
||||||
public const string None = "none";
|
public const string None = "none";
|
||||||
public const string agentTag = "proxy";
|
public const string ProxyTag = "proxy";
|
||||||
public const string directTag = "direct";
|
public const string DirectTag = "direct";
|
||||||
public const string blockTag = "block";
|
public const string BlockTag = "block";
|
||||||
public const string StreamSecurity = "tls";
|
public const string StreamSecurity = "tls";
|
||||||
public const string StreamSecurityReality = "reality";
|
public const string StreamSecurityReality = "reality";
|
||||||
public const string InboundSocks = "socks";
|
|
||||||
public const string InboundHttp = "http";
|
|
||||||
public const string InboundSocks2 = "socks2";
|
|
||||||
public const string InboundHttp2 = "http2";
|
|
||||||
public const string Loopback = "127.0.0.1";
|
public const string Loopback = "127.0.0.1";
|
||||||
public const string InboundAPITagName = "api";
|
public const string InboundAPIProtocol = "dokodemo-door";
|
||||||
public const string InboundAPIProtocal = "dokodemo-door";
|
public const string HttpProtocol = "http://";
|
||||||
|
public const string HttpsProtocol = "https://";
|
||||||
|
|
||||||
public const string vmessProtocol = "vmess://";
|
public const string UserEMail = "t@t.tt";
|
||||||
public const string vmessProtocolLite = "vmess";
|
|
||||||
public const string ssProtocol = "ss://";
|
|
||||||
public const string ssProtocolLite = "shadowsocks";
|
|
||||||
public const string socksProtocol = "socks://";
|
|
||||||
public const string socksProtocolLite = "socks";
|
|
||||||
public const string httpProtocol = "http://";
|
|
||||||
public const string httpsProtocol = "https://";
|
|
||||||
public const string vlessProtocol = "vless://";
|
|
||||||
public const string vlessProtocolLite = "vless";
|
|
||||||
public const string trojanProtocol = "trojan://";
|
|
||||||
public const string trojanProtocolLite = "trojan";
|
|
||||||
|
|
||||||
public const string userEMail = "t@t.tt";
|
|
||||||
public const string MyRegPath = "Software\\v2rayNGUI";
|
|
||||||
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||||
public const string AutoRunName = "v2rayNAutoRun";
|
public const string AutoRunName = "v2rayNAutoRun";
|
||||||
public const string MyRegKeyLanguage = "CurrentLanguage";
|
|
||||||
public const string CustomIconName = "v2rayN.ico";
|
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 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 RoutingRuleComma = "<COMMA>";
|
public const string RoutingRuleComma = "<COMMA>";
|
||||||
public const string GrpcgunMode = "gun";
|
public const string GrpcGunMode = "gun";
|
||||||
public const string GrpcmultiMode = "multi";
|
public const string GrpcMultiMode = "multi";
|
||||||
public const int MaxPort = 65536;
|
public const int MaxPort = 65536;
|
||||||
public const string CommandClearMsg = "CommandClearMsg";
|
public const string CommandClearMsg = "CommandClearMsg";
|
||||||
|
public const string CommandSendMsgView = "CommandSendMsgView";
|
||||||
|
public const string CommandStopSpeedTest = "CommandStopSpeedTest";
|
||||||
public const string DelayUnit = "";
|
public const string DelayUnit = "";
|
||||||
public const string SpeedUnit = "";
|
public const string SpeedUnit = "";
|
||||||
public const int MinFontSize = 10;
|
public const int MinFontSize = 10;
|
||||||
@@ -111,11 +103,20 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
public static readonly List<string> SpeedTestUrls = new() {
|
public static readonly List<string> SpeedTestUrls = new() {
|
||||||
|
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
||||||
|
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
||||||
|
@"http://cachefly.cachefly.net/50mb.test",
|
||||||
@"http://cachefly.cachefly.net/100mb.test",
|
@"http://cachefly.cachefly.net/100mb.test",
|
||||||
@"http://cachefly.cachefly.net/10mb.test"
|
@"http://cachefly.cachefly.net/10mb.test"
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly Dictionary<string, string> userAgentTxt = new()
|
public static readonly List<string> SpeedPingTestUrls = new() {
|
||||||
|
@"https://www.google.com/generate_204",
|
||||||
|
@"https://www.apple.com/library/test/success.html",
|
||||||
|
@"http://www.msftconnecttest.com/connecttest.txt",
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly Dictionary<string, string> UserAgentTexts = new()
|
||||||
{
|
{
|
||||||
{"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
|
{"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
|
||||||
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
|
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
|
||||||
@@ -124,40 +125,63 @@
|
|||||||
{"none",""}
|
{"none",""}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly List<string> vmessSecuritys = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
|
public const string Hysteria2ProtocolShare = "hy2://";
|
||||||
public static readonly List<string> ssSecuritys = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
|
|
||||||
public static readonly List<string> ssSecuritysInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
|
|
||||||
public static readonly List<string> ssSecuritysInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
|
|
||||||
public static readonly List<string> flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
|
||||||
public static readonly List<string> networks = new() { "tcp", "kcp", "ws", "h2", "quic", "grpc" };
|
|
||||||
public static readonly List<string> kcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
|
||||||
public static readonly List<string> coreTypes = new() { "v2fly", "SagerNet", "Xray", "v2fly_v5" };
|
|
||||||
public static readonly List<string> coreTypes4VLESS = new() { "Xray" };
|
|
||||||
public static readonly List<string> domainStrategys = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
|
|
||||||
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> allowInsecures = new() { "true", "false", "" };
|
public static readonly Dictionary<EConfigType, string> ProtocolShares = new()
|
||||||
public static readonly List<string> domainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
|
{
|
||||||
public static readonly List<string> Languages = new() { "zh-Hans", "en", "fa-Ir", "ru" };
|
{EConfigType.VMess,"vmess://"},
|
||||||
public static readonly List<string> alpns = new() { "h2", "http/1.1", "h2,http/1.1", "" };
|
{EConfigType.Shadowsocks,"ss://"},
|
||||||
public static readonly List<string> LogLevel = new() { "debug", "info", "warning", "error", "none" };
|
{EConfigType.Socks,"socks://"},
|
||||||
|
{EConfigType.VLESS,"vless://"},
|
||||||
|
{EConfigType.Trojan,"trojan://"},
|
||||||
|
{EConfigType.Hysteria2,"hysteria2://"},
|
||||||
|
{EConfigType.Tuic,"tuic://"},
|
||||||
|
{EConfigType.Wireguard,"wireguard://"}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
|
||||||
|
{
|
||||||
|
{EConfigType.VMess,"vmess"},
|
||||||
|
{EConfigType.Shadowsocks,"shadowsocks"},
|
||||||
|
{EConfigType.Socks,"socks"},
|
||||||
|
{EConfigType.Http,"http"},
|
||||||
|
{EConfigType.VLESS,"vless"},
|
||||||
|
{EConfigType.Trojan,"trojan"},
|
||||||
|
{EConfigType.Hysteria2,"hysteria2"},
|
||||||
|
{EConfigType.Tuic,"tuic"},
|
||||||
|
{EConfigType.Wireguard,"wireguard"}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
|
||||||
|
public static readonly List<string> SsSecurities = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
|
||||||
|
public static readonly List<string> SsSecuritiesInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
|
||||||
|
public static readonly List<string> SsSecuritiesInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
|
||||||
|
public static readonly List<string> SsSecuritiesInSingbox = new() { "aes-256-gcm", "aes-192-gcm", "aes-128-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20" };
|
||||||
|
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
||||||
|
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "h2", "quic", "grpc" };
|
||||||
|
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
||||||
|
public static readonly List<string> CoreTypes = new() { "v2fly", "SagerNet", "Xray", "sing_box" };
|
||||||
|
public static readonly List<string> CoreTypes4VLESS = 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> AllowInsecure = new() { "true", "false", "" };
|
||||||
|
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
|
||||||
|
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
|
||||||
|
public static readonly List<string> Alpns = new() { "h3", "h2", "http/1.1", "h3,h2,http/1.1", "h3,h2", "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", "http", "socks2", "http2" };
|
||||||
public static readonly List<string> Protocols = new() { "http", "tls", "bittorrent" };
|
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
|
||||||
public static readonly List<string> TunMtus = new() { "9000", "1500" };
|
public static readonly List<string> destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"];
|
||||||
|
public static readonly List<string> TunMtus = new() { "1280", "1408", "1500", "9000" };
|
||||||
public static readonly List<string> TunStacks = new() { "gvisor", "system" };
|
public static readonly List<string> TunStacks = new() { "gvisor", "system" };
|
||||||
public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
|
public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
|
||||||
|
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
|
||||||
|
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
|
||||||
|
|
||||||
#endregion const
|
#endregion const
|
||||||
|
|
||||||
#region global variable
|
|
||||||
|
|
||||||
public static int statePort { get; set; }
|
|
||||||
public static Job processJob { get; set; }
|
|
||||||
public static bool ShowInTaskbar { get; set; }
|
|
||||||
public static string ExePathKey { get; set; }
|
|
||||||
|
|
||||||
#endregion global variable
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Reactive.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
@@ -11,35 +12,30 @@ namespace v2rayN.Handler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class CoreHandler
|
internal class CoreHandler
|
||||||
{
|
{
|
||||||
private static string _coreCConfigRes = Global.coreConfigFileName;
|
private Config _config;
|
||||||
private CoreInfo? _coreInfo;
|
|
||||||
private int _processId = 0;
|
|
||||||
private Process? _process;
|
private Process? _process;
|
||||||
|
private Process? _processPre;
|
||||||
private Action<bool, string> _updateFunc;
|
private Action<bool, string> _updateFunc;
|
||||||
|
|
||||||
public CoreHandler(Action<bool, string> update)
|
public CoreHandler(Config config, Action<bool, string> update)
|
||||||
{
|
{
|
||||||
|
_config = config;
|
||||||
_updateFunc = update;
|
_updateFunc = update;
|
||||||
|
|
||||||
Environment.SetEnvironmentVariable("v2ray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
Environment.SetEnvironmentVariable("v2ray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||||
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadCore(Config config)
|
public void LoadCore()
|
||||||
{
|
{
|
||||||
var node = ConfigHandler.GetDefaultServer(ref config);
|
var node = ConfigHandler.GetDefaultServer(_config);
|
||||||
if (node == null)
|
if (node == null)
|
||||||
{
|
{
|
||||||
ShowMsg(false, ResUI.CheckServerSettings);
|
ShowMsg(false, ResUI.CheckServerSettings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SetCore(config, node) != 0)
|
string fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
|
||||||
{
|
|
||||||
ShowMsg(false, ResUI.CheckServerSettings);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
string fileName = Utils.GetConfigPath(_coreCConfigRes);
|
|
||||||
if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0)
|
if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0)
|
||||||
{
|
{
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
@@ -49,37 +45,47 @@ namespace v2rayN.Handler
|
|||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
ShowMsg(true, $"{node.GetSummary()}");
|
ShowMsg(true, $"{node.GetSummary()}");
|
||||||
CoreStop();
|
CoreStop();
|
||||||
CoreStart(node);
|
if (_config.tunModeItem.enableTun)
|
||||||
}
|
{
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
Utils.RemoveTunDevice();
|
||||||
|
}
|
||||||
|
|
||||||
//start a socks service
|
CoreStart(node);
|
||||||
if (_process != null && !_process.HasExited && node.configType == EConfigType.Custom && node.preSocksPort > 0)
|
|
||||||
{
|
//In tun mode, do a delay check and restart the core
|
||||||
var itemSocks = new ProfileItem()
|
if (_config.tunModeItem.enableTun)
|
||||||
{
|
{
|
||||||
configType = EConfigType.Socks,
|
Observable.Range(1, 1)
|
||||||
address = Global.Loopback,
|
.Delay(TimeSpan.FromSeconds(15))
|
||||||
port = node.preSocksPort
|
.Subscribe(x =>
|
||||||
};
|
{
|
||||||
if (CoreConfigHandler.GenerateClientConfig(itemSocks, null, out string msg2, out string configStr) == 0)
|
{
|
||||||
{
|
if (_process == null || _process.HasExited)
|
||||||
_processId = CoreStartViaString(configStr);
|
{
|
||||||
|
CoreStart(node);
|
||||||
|
ShowMsg(false, "Tun mode restart the core once");
|
||||||
|
Logging.SaveLog("Tun mode restart the core once");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int LoadCoreConfigString(Config config, List<ServerTestItem> _selecteds)
|
public int LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
||||||
{
|
{
|
||||||
int pid = -1;
|
int pid = -1;
|
||||||
string configStr = CoreConfigHandler.GenerateClientSpeedtestConfigString(config, _selecteds, out string msg);
|
var coreType = selecteds.Exists(t => t.configType == EConfigType.Hysteria2 || t.configType == EConfigType.Tuic || t.configType == EConfigType.Wireguard) ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
if (configStr == "")
|
string configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
|
||||||
|
if (CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType, out string msg) != 0)
|
||||||
{
|
{
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
pid = CoreStartViaString(configStr);
|
pid = CoreStartSpeedtest(configPath, coreType);
|
||||||
}
|
}
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
@@ -88,41 +94,50 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
bool hasProc = false;
|
||||||
if (_process != null)
|
if (_process != null)
|
||||||
{
|
{
|
||||||
KillProcess(_process);
|
KillProcess(_process);
|
||||||
_process.Dispose();
|
_process.Dispose();
|
||||||
_process = null;
|
_process = null;
|
||||||
|
hasProc = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (_processPre != null)
|
||||||
{
|
{
|
||||||
if (_coreInfo == null || _coreInfo.coreExes == null)
|
KillProcess(_processPre);
|
||||||
|
_processPre.Dispose();
|
||||||
|
_processPre = null;
|
||||||
|
hasProc = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasProc)
|
||||||
|
{
|
||||||
|
var coreInfo = LazyConfig.Instance.GetCoreInfo();
|
||||||
|
foreach (var it in coreInfo)
|
||||||
{
|
{
|
||||||
return;
|
if (it.coreType == ECoreType.v2rayN)
|
||||||
}
|
|
||||||
foreach (string vName in _coreInfo.coreExes)
|
|
||||||
{
|
|
||||||
Process[] existing = Process.GetProcessesByName(vName);
|
|
||||||
foreach (Process p in existing)
|
|
||||||
{
|
{
|
||||||
string? path = p.MainModule?.FileName;
|
continue;
|
||||||
if (path == $"{Utils.GetBinPath(vName, _coreInfo.coreType)}.exe")
|
}
|
||||||
|
foreach (string vName in it.coreExes)
|
||||||
|
{
|
||||||
|
var existing = Process.GetProcessesByName(vName);
|
||||||
|
foreach (Process p in existing)
|
||||||
{
|
{
|
||||||
KillProcess(p);
|
string? path = p.MainModule?.FileName;
|
||||||
|
if (path == $"{Utils.GetBinPath(vName, it.coreType.ToString())}.exe")
|
||||||
|
{
|
||||||
|
KillProcess(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_processId > 0)
|
|
||||||
{
|
|
||||||
CoreStopPid(_processId);
|
|
||||||
_processId = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,22 +145,24 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Process _p = Process.GetProcessById(pid);
|
var _p = Process.GetProcessById(pid);
|
||||||
KillProcess(_p);
|
KillProcess(_p);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string CoreFindexe(CoreInfo coreInfo)
|
#region Private
|
||||||
|
|
||||||
|
private string CoreFindExe(CoreInfo coreInfo)
|
||||||
{
|
{
|
||||||
string fileName = string.Empty;
|
string fileName = string.Empty;
|
||||||
foreach (string name in coreInfo.coreExes)
|
foreach (string name in coreInfo.coreExes)
|
||||||
{
|
{
|
||||||
string vName = $"{name}.exe";
|
string vName = $"{name}.exe";
|
||||||
vName = Utils.GetBinPath(vName, coreInfo.coreType);
|
vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString());
|
||||||
if (File.Exists(vName))
|
if (File.Exists(vName))
|
||||||
{
|
{
|
||||||
fileName = vName;
|
fileName = vName;
|
||||||
@@ -154,8 +171,8 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
|
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType.ToString()), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
|
||||||
Utils.SaveLog(msg);
|
Logging.SaveLog(msg);
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
}
|
}
|
||||||
return fileName;
|
return fileName;
|
||||||
@@ -163,20 +180,106 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
private void CoreStart(ProfileItem node)
|
private void CoreStart(ProfileItem node)
|
||||||
{
|
{
|
||||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString()));
|
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||||
|
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||||
|
|
||||||
|
ECoreType coreType;
|
||||||
|
if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
|
||||||
|
{
|
||||||
|
coreType = ECoreType.sing_box;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
||||||
|
}
|
||||||
|
_config.runningCoreType = coreType;
|
||||||
|
var coreInfo = LazyConfig.Instance.GetCoreInfo(coreType);
|
||||||
|
|
||||||
|
var displayLog = node.configType != EConfigType.Custom || node.displayLog;
|
||||||
|
var proc = RunProcess(node, coreInfo, "", displayLog);
|
||||||
|
if (proc is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_process = proc;
|
||||||
|
|
||||||
|
//start a socks service
|
||||||
|
if (_process != null && !_process.HasExited)
|
||||||
|
{
|
||||||
|
if ((node.configType == EConfigType.Custom && node.preSocksPort > 0))
|
||||||
|
{
|
||||||
|
var preCoreType = _config.tunModeItem.enableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
|
var itemSocks = new ProfileItem()
|
||||||
|
{
|
||||||
|
coreType = preCoreType,
|
||||||
|
configType = EConfigType.Socks,
|
||||||
|
address = Global.Loopback,
|
||||||
|
port = node.preSocksPort
|
||||||
|
};
|
||||||
|
_config.runningCoreType = preCoreType;
|
||||||
|
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
|
||||||
|
if (CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2, out string msg2, out string configStr) == 0)
|
||||||
|
{
|
||||||
|
var coreInfo2 = LazyConfig.Instance.GetCoreInfo(preCoreType);
|
||||||
|
var proc2 = RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true);
|
||||||
|
if (proc2 is not null)
|
||||||
|
{
|
||||||
|
_processPre = proc2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int CoreStartSpeedtest(string configPath, ECoreType coreType)
|
||||||
|
{
|
||||||
|
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||||
|
|
||||||
|
ShowMsg(false, configPath);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string fileName = CoreFindexe(_coreInfo);
|
var coreInfo = LazyConfig.Instance.GetCoreInfo(coreType);
|
||||||
if (fileName == "") return;
|
var proc = RunProcess(new(), coreInfo, $" -c {Global.CoreSpeedtestConfigFileName}", true);
|
||||||
|
if (proc is null)
|
||||||
var displayLog = node.configType != EConfigType.Custom || node.displayLog;
|
|
||||||
Process p = new()
|
|
||||||
{
|
{
|
||||||
StartInfo = new ProcessStartInfo
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return proc.Id;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
string msg = ex.Message;
|
||||||
|
ShowMsg(false, msg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowMsg(bool notify, string msg)
|
||||||
|
{
|
||||||
|
_updateFunc(notify, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Private
|
||||||
|
|
||||||
|
#region Process
|
||||||
|
|
||||||
|
private Process? RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string fileName = CoreFindExe(coreInfo);
|
||||||
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Process proc = new()
|
||||||
|
{
|
||||||
|
StartInfo = new()
|
||||||
{
|
{
|
||||||
FileName = fileName,
|
FileName = fileName,
|
||||||
Arguments = _coreInfo.arguments,
|
Arguments = string.Format(coreInfo.arguments, configPath),
|
||||||
WorkingDirectory = Utils.GetConfigPath(),
|
WorkingDirectory = Utils.GetConfigPath(),
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
RedirectStandardOutput = displayLog,
|
RedirectStandardOutput = displayLog,
|
||||||
@@ -186,153 +289,83 @@ namespace v2rayN.Handler
|
|||||||
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
|
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
var startUpErrorMessage = new StringBuilder();
|
||||||
|
var startUpSuccessful = false;
|
||||||
if (displayLog)
|
if (displayLog)
|
||||||
{
|
{
|
||||||
p.OutputDataReceived += (sender, e) =>
|
proc.OutputDataReceived += (sender, e) =>
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(e.Data))
|
if (!Utils.IsNullOrEmpty(e.Data))
|
||||||
{
|
|
||||||
string msg = e.Data + Environment.NewLine;
|
|
||||||
ShowMsg(false, msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
p.ErrorDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(e.Data))
|
|
||||||
{
|
{
|
||||||
string msg = e.Data + Environment.NewLine;
|
string msg = e.Data + Environment.NewLine;
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
proc.ErrorDataReceived += (sender, e) =>
|
||||||
|
{
|
||||||
|
if (!Utils.IsNullOrEmpty(e.Data))
|
||||||
|
{
|
||||||
|
string msg = e.Data + Environment.NewLine;
|
||||||
|
ShowMsg(false, msg);
|
||||||
|
|
||||||
|
if (!startUpSuccessful)
|
||||||
|
{
|
||||||
|
startUpErrorMessage.Append(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
p.Start();
|
proc.Start();
|
||||||
if (displayLog)
|
if (displayLog)
|
||||||
{
|
{
|
||||||
p.BeginOutputReadLine();
|
proc.BeginOutputReadLine();
|
||||||
p.BeginErrorReadLine();
|
proc.BeginErrorReadLine();
|
||||||
}
|
}
|
||||||
_process = p;
|
|
||||||
|
|
||||||
if (p.WaitForExit(1000))
|
if (proc.WaitForExit(1000))
|
||||||
{
|
{
|
||||||
throw new Exception(displayLog ? p.StandardError.ReadToEnd() : "启动进程失败并退出 (Failed to start the process and exited)");
|
proc.CancelErrorRead();
|
||||||
|
throw new Exception(displayLog ? startUpErrorMessage.ToString() : "启动进程失败并退出 (Failed to start the process and exited)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startUpSuccessful = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Global.processJob.AddProcess(p.Handle);
|
LazyConfig.Instance.AddProcess(proc.Handle);
|
||||||
|
return proc;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
//Utils.SaveLog(Utils.ToJson(node));
|
Logging.SaveLog(ex.Message, ex);
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
string msg = ex.Message;
|
string msg = ex.Message;
|
||||||
ShowMsg(true, msg);
|
ShowMsg(true, msg);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CoreStartViaString(string configStr)
|
private void KillProcess(Process? proc)
|
||||||
{
|
{
|
||||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString()));
|
if (proc is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(ECoreType.Xray);
|
proc.Kill();
|
||||||
string fileName = CoreFindexe(coreInfo);
|
proc.WaitForExit(100);
|
||||||
if (fileName == "") return -1;
|
if (!proc.HasExited)
|
||||||
|
|
||||||
Process p = new()
|
|
||||||
{
|
{
|
||||||
StartInfo = new ProcessStartInfo
|
proc.Kill();
|
||||||
{
|
proc.WaitForExit(100);
|
||||||
FileName = fileName,
|
|
||||||
Arguments = "-config stdin:",
|
|
||||||
WorkingDirectory = Utils.GetConfigPath(),
|
|
||||||
UseShellExecute = false,
|
|
||||||
RedirectStandardInput = true,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
StandardOutputEncoding = Encoding.UTF8,
|
|
||||||
StandardErrorEncoding = Encoding.UTF8
|
|
||||||
}
|
|
||||||
};
|
|
||||||
p.OutputDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (!String.IsNullOrEmpty(e.Data))
|
|
||||||
{
|
|
||||||
string msg = e.Data + Environment.NewLine;
|
|
||||||
ShowMsg(false, msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
p.ErrorDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(e.Data))
|
|
||||||
{
|
|
||||||
string msg = e.Data + Environment.NewLine;
|
|
||||||
ShowMsg(false, msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
p.Start();
|
|
||||||
p.BeginOutputReadLine();
|
|
||||||
p.BeginErrorReadLine();
|
|
||||||
|
|
||||||
p.StandardInput.Write(configStr);
|
|
||||||
p.StandardInput.Close();
|
|
||||||
|
|
||||||
if (p.WaitForExit(1000))
|
|
||||||
{
|
|
||||||
throw new Exception(p.StandardError.ReadToEnd());
|
|
||||||
}
|
|
||||||
|
|
||||||
Global.processJob.AddProcess(p.Handle);
|
|
||||||
return p.Id;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
string msg = ex.Message;
|
|
||||||
ShowMsg(false, msg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ShowMsg(bool updateToTrayTooltip, string msg)
|
|
||||||
{
|
|
||||||
_updateFunc(updateToTrayTooltip, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void KillProcess(Process p)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
p.CloseMainWindow();
|
|
||||||
p.WaitForExit(100);
|
|
||||||
if (!p.HasExited)
|
|
||||||
{
|
|
||||||
p.Kill();
|
|
||||||
p.WaitForExit(100);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int SetCore(Config config, ProfileItem node)
|
#endregion Process
|
||||||
{
|
|
||||||
if (node == null)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
|
||||||
|
|
||||||
_coreInfo = LazyConfig.Instance.GetCoreInfo(coreType);
|
|
||||||
|
|
||||||
if (_coreInfo == null)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ using System.Net;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using v2rayN.Base;
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
@@ -62,12 +62,12 @@ namespace v2rayN.Handler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DownloadFileAsync(string url, bool blProxy, int downloadTimeout)
|
public async Task DownloadFileAsync(string url, bool blProxy, int downloadTimeout)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
|
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
|
||||||
UpdateCompleted?.Invoke(this, new ResultEventArgs(false, ResUI.Downloading));
|
UpdateCompleted?.Invoke(this, new ResultEventArgs(false, $"{ResUI.Downloading} {url}"));
|
||||||
|
|
||||||
var progress = new Progress<double>();
|
var progress = new Progress<double>();
|
||||||
progress.ProgressChanged += (sender, value) =>
|
progress.ProgressChanged += (sender, value) =>
|
||||||
@@ -76,7 +76,7 @@ namespace v2rayN.Handler
|
|||||||
};
|
};
|
||||||
|
|
||||||
var webProxy = GetWebProxy(blProxy);
|
var webProxy = GetWebProxy(blProxy);
|
||||||
_ = DownloaderHelper.Instance.DownloadFileAsync(webProxy,
|
await DownloaderHelper.Instance.DownloadFileAsync(webProxy,
|
||||||
url,
|
url,
|
||||||
Utils.GetTempPath(Utils.GetDownloadFileName(url)),
|
Utils.GetTempPath(Utils.GetDownloadFileName(url)),
|
||||||
progress,
|
progress,
|
||||||
@@ -84,7 +84,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
|
||||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||||
if (ex.InnerException != null)
|
if (ex.InnerException != null)
|
||||||
@@ -111,7 +111,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Utils.SaveLog("StatusCode error: " + url);
|
Logging.SaveLog("StatusCode error: " + url);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,7 +128,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||||
if (ex.InnerException != null)
|
if (ex.InnerException != null)
|
||||||
{
|
{
|
||||||
@@ -146,7 +146,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||||
if (ex.InnerException != null)
|
if (ex.InnerException != null)
|
||||||
{
|
{
|
||||||
@@ -166,7 +166,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||||
if (ex.InnerException != null)
|
if (ex.InnerException != null)
|
||||||
{
|
{
|
||||||
@@ -206,15 +206,13 @@ namespace v2rayN.Handler
|
|||||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Utils.Base64Encode(uri.UserInfo));
|
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Utils.Base64Encode(uri.UserInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
var cts = new CancellationTokenSource();
|
using var cts = new CancellationTokenSource();
|
||||||
cts.CancelAfter(1000 * 30);
|
var result = await HttpClientHelper.Instance.GetAsync(client, url, cts.Token).WaitAsync(TimeSpan.FromSeconds(30), cts.Token);
|
||||||
|
|
||||||
var result = await HttpClientHelper.Instance.GetAsync(client, url, cts.Token);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||||
if (ex.InnerException != null)
|
if (ex.InnerException != null)
|
||||||
{
|
{
|
||||||
@@ -245,7 +243,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
Error?.Invoke(this, new ErrorEventArgs(ex));
|
Error?.Invoke(this, new ErrorEventArgs(ex));
|
||||||
if (ex.InnerException != null)
|
if (ex.InnerException != null)
|
||||||
{
|
{
|
||||||
@@ -255,61 +253,57 @@ namespace v2rayN.Handler
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int RunAvailabilityCheck(IWebProxy? webProxy)
|
public async Task<int> RunAvailabilityCheck(IWebProxy? webProxy)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (webProxy == null)
|
if (webProxy == null)
|
||||||
{
|
{
|
||||||
var httpPort = LazyConfig.Instance.GetLocalPort(Global.InboundHttp);
|
webProxy = GetWebProxy(true);
|
||||||
webProxy = new WebProxy(Global.Loopback, httpPort);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var config = LazyConfig.Instance.GetConfig();
|
var config = LazyConfig.Instance.GetConfig();
|
||||||
string status = GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10, out int responseTime);
|
int responseTime = await GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10);
|
||||||
bool noError = Utils.IsNullOrEmpty(status);
|
return responseTime;
|
||||||
return noError ? responseTime : -1;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetRealPingTime(string url, IWebProxy? webProxy, int downloadTimeout, out int responseTime)
|
public async Task<int> GetRealPingTime(string url, IWebProxy? webProxy, int downloadTimeout)
|
||||||
{
|
{
|
||||||
string msg = string.Empty;
|
int responseTime = -1;
|
||||||
responseTime = -1;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
|
|
||||||
myHttpWebRequest.Timeout = downloadTimeout * 1000;
|
|
||||||
myHttpWebRequest.Proxy = webProxy;
|
|
||||||
|
|
||||||
Stopwatch timer = Stopwatch.StartNew();
|
Stopwatch timer = Stopwatch.StartNew();
|
||||||
|
|
||||||
using HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
|
using var cts = new CancellationTokenSource();
|
||||||
if (myHttpWebResponse.StatusCode is not HttpStatusCode.OK and not HttpStatusCode.NoContent)
|
cts.CancelAfter(TimeSpan.FromSeconds(downloadTimeout));
|
||||||
|
using var client = new HttpClient(new SocketsHttpHandler()
|
||||||
{
|
{
|
||||||
msg = myHttpWebResponse.StatusDescription;
|
Proxy = webProxy,
|
||||||
}
|
UseProxy = webProxy != null
|
||||||
|
});
|
||||||
|
await client.GetAsync(url, cts.Token);
|
||||||
|
|
||||||
responseTime = timer.Elapsed.Milliseconds;
|
responseTime = timer.Elapsed.Milliseconds;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch //(Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
//Utile.SaveLog(ex.Message, ex);
|
||||||
msg = ex.Message;
|
|
||||||
}
|
}
|
||||||
return msg;
|
return responseTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WebProxy? GetWebProxy(bool blProxy)
|
private WebProxy? GetWebProxy(bool blProxy)
|
||||||
@@ -318,7 +312,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var httpPort = LazyConfig.Instance.GetLocalPort(Global.InboundHttp);
|
var httpPort = LazyConfig.Instance.GetLocalPort(EInboundProtocol.http);
|
||||||
if (!SocketCheck(Global.Loopback, httpPort))
|
if (!SocketCheck(Global.Loopback, httpPort))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using System.Text;
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
@@ -113,9 +113,9 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
var mdif = (KeyModifiers)_fsModifiers;
|
var mdif = (KeyModifiers)_fsModifiers;
|
||||||
var key = KeyInterop.KeyFromVirtualKey(_vkey);
|
var key = KeyInterop.KeyFromVirtualKey(_vkey);
|
||||||
if ((mdif | KeyModifiers.Ctrl) == KeyModifiers.Ctrl) _hotkeyStr.Append($"{KeyModifiers.Ctrl}+");
|
if ((mdif & KeyModifiers.Ctrl) == KeyModifiers.Ctrl) _hotkeyStr.Append($"{KeyModifiers.Ctrl}+");
|
||||||
if ((mdif | KeyModifiers.Alt) == KeyModifiers.Alt) _hotkeyStr.Append($"{KeyModifiers.Alt}+");
|
if ((mdif & KeyModifiers.Alt) == KeyModifiers.Alt) _hotkeyStr.Append($"{KeyModifiers.Alt}+");
|
||||||
if ((mdif | KeyModifiers.Shift) == KeyModifiers.Shift) _hotkeyStr.Append($"{KeyModifiers.Shift}+");
|
if ((mdif & KeyModifiers.Shift) == KeyModifiers.Shift) _hotkeyStr.Append($"{KeyModifiers.Shift}+");
|
||||||
_hotkeyStr.Append(key.ToString());
|
_hotkeyStr.Append(key.ToString());
|
||||||
|
|
||||||
foreach (var name in _hotkeyTriggerDic[hotkeycode])
|
foreach (var name in _hotkeyTriggerDic[hotkeycode])
|
||||||
|
|||||||
+172
-115
@@ -1,5 +1,5 @@
|
|||||||
using v2rayN.Base;
|
using System.Runtime.Intrinsics.X86;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Models;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
@@ -7,17 +7,35 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
private static readonly Lazy<LazyConfig> _instance = new(() => new());
|
private static readonly Lazy<LazyConfig> _instance = new(() => new());
|
||||||
private Config _config;
|
private Config _config;
|
||||||
private List<CoreInfo> coreInfos;
|
private List<CoreInfo> coreInfo;
|
||||||
|
|
||||||
public static LazyConfig Instance => _instance.Value;
|
public static LazyConfig Instance => _instance.Value;
|
||||||
|
|
||||||
|
private int? _statePort;
|
||||||
|
|
||||||
|
public int StatePort
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_statePort is null)
|
||||||
|
{
|
||||||
|
_statePort = Utils.GetFreePort(GetLocalPort(EInboundProtocol.api));
|
||||||
|
}
|
||||||
|
|
||||||
|
return _statePort.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Job _processJob = new();
|
||||||
|
|
||||||
public LazyConfig()
|
public LazyConfig()
|
||||||
{
|
{
|
||||||
SqliteHelper.Instance.CreateTable<SubItem>();
|
SQLiteHelper.Instance.CreateTable<SubItem>();
|
||||||
SqliteHelper.Instance.CreateTable<ProfileItem>();
|
SQLiteHelper.Instance.CreateTable<ProfileItem>();
|
||||||
SqliteHelper.Instance.CreateTable<ServerStatItem>();
|
SQLiteHelper.Instance.CreateTable<ServerStatItem>();
|
||||||
SqliteHelper.Instance.CreateTable<RoutingItem>();
|
SQLiteHelper.Instance.CreateTable<RoutingItem>();
|
||||||
SqliteHelper.Instance.CreateTable<ProfileExItem>();
|
SQLiteHelper.Instance.CreateTable<ProfileExItem>();
|
||||||
|
SQLiteHelper.Instance.CreateTable<DNSItem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Config
|
#region Config
|
||||||
@@ -32,67 +50,52 @@ namespace v2rayN.Handler
|
|||||||
return _config;
|
return _config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetLocalPort(string protocol)
|
public int GetLocalPort(EInboundProtocol protocol)
|
||||||
{
|
{
|
||||||
int localPort = _config.inbound.FirstOrDefault(t => t.protocol == Global.InboundSocks).localPort;
|
var localPort = _config.inbound.FirstOrDefault(t => t.protocol == nameof(EInboundProtocol.socks))?.localPort ?? 10808;
|
||||||
if (protocol == Global.InboundSocks)
|
return localPort + (int)protocol;
|
||||||
{
|
|
||||||
return localPort;
|
|
||||||
}
|
|
||||||
else if (protocol == Global.InboundHttp)
|
|
||||||
{
|
|
||||||
return localPort + 1;
|
|
||||||
}
|
|
||||||
else if (protocol == Global.InboundSocks2)
|
|
||||||
{
|
|
||||||
return localPort + 2;
|
|
||||||
}
|
|
||||||
else if (protocol == Global.InboundHttp2)
|
|
||||||
{
|
|
||||||
return localPort + 3;
|
|
||||||
}
|
|
||||||
else if (protocol == ESysProxyType.Pac.ToString())
|
|
||||||
{
|
|
||||||
return localPort + 4;
|
|
||||||
}
|
|
||||||
else if (protocol == "speedtest")
|
|
||||||
{
|
|
||||||
return localPort + 103;
|
|
||||||
}
|
|
||||||
return localPort;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddProcess(IntPtr processHandle)
|
||||||
|
{
|
||||||
|
_processJob.AddProcess(processHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Config
|
||||||
|
|
||||||
|
#region SqliteHelper
|
||||||
|
|
||||||
public List<SubItem> SubItems()
|
public List<SubItem> SubItems()
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<SubItem>().ToList();
|
return SQLiteHelper.Instance.Table<SubItem>().ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubItem GetSubItem(string subid)
|
public SubItem GetSubItem(string subid)
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<SubItem>().FirstOrDefault(t => t.id == subid);
|
return SQLiteHelper.Instance.Table<SubItem>().FirstOrDefault(t => t.id == subid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ProfileItem> ProfileItems(string subid)
|
public List<ProfileItem> ProfileItems(string subid)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(subid))
|
if (Utils.IsNullOrEmpty(subid))
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<ProfileItem>().ToList();
|
return SQLiteHelper.Instance.Table<ProfileItem>().ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).ToList();
|
return SQLiteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> ProfileItemIndexs(string subid)
|
public List<string> ProfileItemIndexes(string subid)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(subid))
|
if (Utils.IsNullOrEmpty(subid))
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<ProfileItem>().Select(t => t.indexId).ToList();
|
return SQLiteHelper.Instance.Table<ProfileItem>().Select(t => t.indexId).ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).Select(t => t.indexId).ToList();
|
return SQLiteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).Select(t => t.indexId).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +119,7 @@ namespace v2rayN.Handler
|
|||||||
sql += String.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter);
|
sql += String.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SqliteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
|
return SQLiteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProfileItem? GetProfileItem(string indexId)
|
public ProfileItem? GetProfileItem(string indexId)
|
||||||
@@ -125,35 +128,57 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId);
|
return SQLiteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProfileItem? GetProfileItemViaRemarks(string remarks)
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(remarks))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return SQLiteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.remarks == remarks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RoutingItem> RoutingItems()
|
public List<RoutingItem> RoutingItems()
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).OrderBy(t => t.sort).ToList();
|
return SQLiteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).OrderBy(t => t.sort).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public RoutingItem GetRoutingItem(string id)
|
public RoutingItem GetRoutingItem(string id)
|
||||||
{
|
{
|
||||||
return SqliteHelper.Instance.Table<RoutingItem>().FirstOrDefault(it => it.locked == false && it.id == id);
|
return SQLiteHelper.Instance.Table<RoutingItem>().FirstOrDefault(it => it.locked == false && it.id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Config
|
public List<DNSItem> DNSItems()
|
||||||
|
{
|
||||||
|
return SQLiteHelper.Instance.Table<DNSItem>().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DNSItem GetDNSItem(ECoreType eCoreType)
|
||||||
|
{
|
||||||
|
return SQLiteHelper.Instance.Table<DNSItem>().FirstOrDefault(it => it.coreType == eCoreType);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion SqliteHelper
|
||||||
|
|
||||||
#region Core Type
|
#region Core Type
|
||||||
|
|
||||||
public List<string> GetShadowsocksSecuritys(ProfileItem profileItem)
|
public List<string> GetShadowsocksSecurities(ProfileItem profileItem)
|
||||||
{
|
{
|
||||||
if (GetCoreType(profileItem, EConfigType.Shadowsocks) == ECoreType.v2fly)
|
var coreType = GetCoreType(profileItem, EConfigType.Shadowsocks);
|
||||||
|
switch (coreType)
|
||||||
{
|
{
|
||||||
return Global.ssSecuritys;
|
case ECoreType.v2fly:
|
||||||
}
|
return Global.SsSecurities;
|
||||||
if (GetCoreType(profileItem, EConfigType.Shadowsocks) == ECoreType.Xray)
|
|
||||||
{
|
|
||||||
return Global.ssSecuritysInXray;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Global.ssSecuritysInSagerNet;
|
case ECoreType.Xray:
|
||||||
|
return Global.SsSecuritiesInXray;
|
||||||
|
|
||||||
|
case ECoreType.sing_box:
|
||||||
|
return Global.SsSecuritiesInSingbox;
|
||||||
|
}
|
||||||
|
return Global.SsSecuritiesInSagerNet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
|
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
|
||||||
@@ -177,58 +202,58 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
public CoreInfo? GetCoreInfo(ECoreType coreType)
|
public CoreInfo? GetCoreInfo(ECoreType coreType)
|
||||||
{
|
{
|
||||||
if (coreInfos == null)
|
if (coreInfo == null)
|
||||||
{
|
{
|
||||||
InitCoreInfo();
|
InitCoreInfo();
|
||||||
}
|
}
|
||||||
return coreInfos!.FirstOrDefault(t => t.coreType == coreType);
|
return coreInfo?.FirstOrDefault(t => t.coreType == coreType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CoreInfo>? GetCoreInfos()
|
public List<CoreInfo> GetCoreInfo()
|
||||||
{
|
{
|
||||||
if (coreInfos == null)
|
if (coreInfo == null)
|
||||||
{
|
{
|
||||||
InitCoreInfo();
|
InitCoreInfo();
|
||||||
}
|
}
|
||||||
return coreInfos;
|
return coreInfo!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitCoreInfo()
|
private void InitCoreInfo()
|
||||||
{
|
{
|
||||||
coreInfos = new(16);
|
coreInfo = new(16);
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.v2rayN,
|
coreType = ECoreType.v2rayN,
|
||||||
coreUrl = Global.NUrl,
|
coreUrl = Global.NUrl,
|
||||||
coreReleaseApiUrl = Global.NUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
coreReleaseApiUrl = Global.NUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN-32.zip",
|
coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN-32.zip",
|
||||||
coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip",
|
coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip",
|
||||||
coreDownloadUrlArm64 = Global.NUrl + "/download/{0}/v2rayN-arm64.zip"
|
coreDownloadUrlArm64 = Global.NUrl + "/download/{0}/v2rayN-arm64.zip"
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.v2fly,
|
coreType = ECoreType.v2fly,
|
||||||
coreExes = new List<string> { "wv2ray", "v2ray" },
|
coreExes = new List<string> { "wv2ray", "v2ray" },
|
||||||
arguments = "",
|
arguments = "",
|
||||||
coreUrl = Global.v2flyCoreUrl,
|
coreUrl = Global.V2flyCoreUrl,
|
||||||
coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
coreReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
coreDownloadUrl32 = Global.V2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||||
coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
coreDownloadUrl64 = Global.V2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||||
coreDownloadUrlArm64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
coreDownloadUrlArm64 = Global.V2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||||
match = "V2Ray",
|
match = "V2Ray",
|
||||||
versionArg = "-version",
|
versionArg = "-version",
|
||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.SagerNet,
|
coreType = ECoreType.SagerNet,
|
||||||
coreExes = new List<string> { "SagerNet", "v2ray" },
|
coreExes = new List<string> { "SagerNet", "v2ray" },
|
||||||
arguments = "run",
|
arguments = "run",
|
||||||
coreUrl = Global.SagerNetCoreUrl,
|
coreUrl = Global.SagerNetCoreUrl,
|
||||||
coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
coreDownloadUrl32 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
coreDownloadUrl32 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||||
coreDownloadUrl64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
coreDownloadUrl64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||||
coreDownloadUrlArm64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
coreDownloadUrlArm64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||||
@@ -237,111 +262,143 @@ namespace v2rayN.Handler
|
|||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.v2fly_v5,
|
coreType = ECoreType.v2fly_v5,
|
||||||
coreExes = new List<string> { "v2ray" },
|
coreExes = new List<string> { "v2ray" },
|
||||||
arguments = "run",
|
arguments = "run -c config.json -format jsonv5",
|
||||||
coreUrl = Global.v2flyCoreUrl,
|
coreUrl = Global.V2flyCoreUrl,
|
||||||
coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
coreReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
coreDownloadUrl32 = Global.V2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||||
coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
coreDownloadUrl64 = Global.V2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||||
coreDownloadUrlArm64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
coreDownloadUrlArm64 = Global.V2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
|
||||||
match = "V2Ray",
|
match = "V2Ray",
|
||||||
versionArg = "version",
|
versionArg = "version",
|
||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.Xray,
|
coreType = ECoreType.Xray,
|
||||||
coreExes = new List<string> { "xray", "wxray" },
|
coreExes = new List<string> { "xray", "wxray" },
|
||||||
arguments = "",
|
arguments = "run {0}",
|
||||||
coreUrl = Global.xrayCoreUrl,
|
coreUrl = Global.XrayCoreUrl,
|
||||||
coreReleaseApiUrl = Global.xrayCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
coreReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
coreDownloadUrl32 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
|
coreDownloadUrl32 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
|
||||||
coreDownloadUrl64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
|
coreDownloadUrl64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
|
||||||
coreDownloadUrlArm64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
|
coreDownloadUrlArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
|
||||||
match = "Xray",
|
match = "Xray",
|
||||||
versionArg = "-version",
|
versionArg = "-version",
|
||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.clash,
|
coreType = ECoreType.clash,
|
||||||
coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" },
|
coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" },
|
||||||
arguments = "-f config.json",
|
arguments = "-f config.json",
|
||||||
coreUrl = Global.clashCoreUrl,
|
coreUrl = Global.ClashCoreUrl,
|
||||||
coreReleaseApiUrl = Global.clashCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
coreReleaseApiUrl = Global.ClashCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
coreDownloadUrl32 = Global.clashCoreUrl + "/download/{0}/clash-windows-386-{0}.zip",
|
coreDownloadUrl32 = Global.ClashCoreUrl + "/download/{0}/clash-windows-386-{0}.zip",
|
||||||
coreDownloadUrl64 = Global.clashCoreUrl + "/download/{0}/clash-windows-amd64-{0}.zip",
|
coreDownloadUrl64 = Global.ClashCoreUrl + "/download/{0}/clash-windows-amd64-{0}.zip",
|
||||||
coreDownloadUrlArm64 = Global.clashCoreUrl + "/download/{0}/clash-windows-arm64-{0}.zip",
|
coreDownloadUrlArm64 = Global.ClashCoreUrl + "/download/{0}/clash-windows-arm64-{0}.zip",
|
||||||
match = "v",
|
match = "v",
|
||||||
versionArg = "-v",
|
versionArg = "-v",
|
||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.clash_meta,
|
coreType = ECoreType.clash_meta,
|
||||||
coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" },
|
coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" },
|
||||||
arguments = "-f config.json",
|
arguments = "-f config.json",
|
||||||
coreUrl = Global.clashMetaCoreUrl,
|
coreUrl = Global.ClashMetaCoreUrl,
|
||||||
coreReleaseApiUrl = Global.clashMetaCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
coreReleaseApiUrl = Global.ClashMetaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
coreDownloadUrl32 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-386-{0}.zip",
|
coreDownloadUrl32 = Global.ClashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-386-{0}.zip",
|
||||||
coreDownloadUrl64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-amd64-compatible-{0}.zip",
|
coreDownloadUrl64 = Global.ClashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-amd64-compatible-{0}.zip",
|
||||||
coreDownloadUrlArm64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-arm64-{0}.zip",
|
coreDownloadUrlArm64 = Global.ClashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-arm64-{0}.zip",
|
||||||
match = "v",
|
match = "v",
|
||||||
versionArg = "-v",
|
versionArg = "-v",
|
||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.mihomo,
|
||||||
|
coreExes = new List<string> { $"mihomo-windows-amd64{(Avx2.X64.IsSupported ? "" : "-compatible")}", "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-windows-386", "mihomo", "clash" },
|
||||||
|
arguments = "-f config.json",
|
||||||
|
coreUrl = Global.MihomoCoreUrl,
|
||||||
|
coreReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
match = "Mihomo",
|
||||||
|
redirectInfo = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.hysteria,
|
coreType = ECoreType.hysteria,
|
||||||
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
||||||
arguments = "",
|
arguments = "",
|
||||||
coreUrl = Global.hysteriaCoreUrl,
|
coreUrl = Global.HysteriaCoreUrl,
|
||||||
coreReleaseApiUrl = Global.hysteriaCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
coreReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
coreDownloadUrl32 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-386.exe",
|
coreDownloadUrl32 = Global.HysteriaCoreUrl + "/download/{0}/hysteria-windows-386.exe",
|
||||||
coreDownloadUrl64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-amd64.exe",
|
coreDownloadUrl64 = Global.HysteriaCoreUrl + "/download/{0}/hysteria-windows-amd64.exe",
|
||||||
coreDownloadUrlArm64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-arm64.exe",
|
coreDownloadUrlArm64 = Global.HysteriaCoreUrl + "/download/{0}/hysteria-windows-arm64.exe",
|
||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.naiveproxy,
|
coreType = ECoreType.naiveproxy,
|
||||||
coreExes = new List<string> { "naiveproxy", "naive" },
|
coreExes = new List<string> { "naiveproxy", "naive" },
|
||||||
arguments = "config.json",
|
arguments = "config.json",
|
||||||
coreUrl = Global.naiveproxyCoreUrl,
|
coreUrl = Global.NaiveproxyCoreUrl,
|
||||||
redirectInfo = false,
|
redirectInfo = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.tuic,
|
coreType = ECoreType.tuic,
|
||||||
coreExes = new List<string> { "tuic-client", "tuic" },
|
coreExes = new List<string> { "tuic-client", "tuic" },
|
||||||
arguments = "-c config.json",
|
arguments = "-c config.json",
|
||||||
coreUrl = Global.tuicCoreUrl,
|
coreUrl = Global.TuicCoreUrl,
|
||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
coreInfos.Add(new CoreInfo
|
coreInfo.Add(new CoreInfo
|
||||||
{
|
{
|
||||||
coreType = ECoreType.sing_box,
|
coreType = ECoreType.sing_box,
|
||||||
coreExes = new List<string> { "sing-box-client", "sing-box" },
|
coreExes = new List<string> { "sing-box-client", "sing-box" },
|
||||||
arguments = "run",
|
arguments = "run {0} --disable-color",
|
||||||
coreUrl = Global.singboxCoreUrl,
|
coreUrl = Global.SingboxCoreUrl,
|
||||||
redirectInfo = true,
|
redirectInfo = true,
|
||||||
coreReleaseApiUrl = Global.singboxCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
|
coreReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
coreDownloadUrl32 = Global.singboxCoreUrl + "/download/{0}/sing-box-{1}-windows-386.zip",
|
coreDownloadUrl32 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-386.zip",
|
||||||
coreDownloadUrl64 = Global.singboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip",
|
coreDownloadUrl64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip",
|
||||||
coreDownloadUrlArm64 = Global.singboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
|
coreDownloadUrlArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
|
||||||
match = "sing-box",
|
match = "sing-box",
|
||||||
versionArg = "version",
|
versionArg = "version",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.juicity,
|
||||||
|
coreExes = new List<string> { "juicity-client", "juicity" },
|
||||||
|
arguments = "run -c config.json",
|
||||||
|
coreUrl = Global.JuicityCoreUrl
|
||||||
|
});
|
||||||
|
|
||||||
|
coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.hysteria2,
|
||||||
|
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
||||||
|
arguments = "",
|
||||||
|
coreUrl = Global.HysteriaCoreUrl,
|
||||||
|
coreReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
coreDownloadUrl32 = Global.HysteriaCoreUrl + "/download/{0}/hysteria-windows-386.exe",
|
||||||
|
coreDownloadUrl64 = Global.HysteriaCoreUrl + "/download/{0}/hysteria-windows-amd64.exe",
|
||||||
|
coreDownloadUrlArm64 = Global.HysteriaCoreUrl + "/download/{0}/hysteria-windows-arm64.exe",
|
||||||
|
redirectInfo = true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Core Type
|
#endregion Core Type
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
using Splat;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
@@ -42,7 +43,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
return Properties.Resources.NotifyIcon1;
|
return Properties.Resources.NotifyIcon1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,18 +51,18 @@ namespace v2rayN.Handler
|
|||||||
public System.Windows.Media.ImageSource GetAppIcon(Config config)
|
public System.Windows.Media.ImageSource GetAppIcon(Config config)
|
||||||
{
|
{
|
||||||
int index = 1;
|
int index = 1;
|
||||||
switch ((int)config.sysProxyType)
|
switch (config.sysProxyType)
|
||||||
{
|
{
|
||||||
case 0:
|
case ESysProxyType.ForcedClear:
|
||||||
index = 1;
|
index = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case ESysProxyType.ForcedChange:
|
||||||
case 3:
|
case ESysProxyType.Pac:
|
||||||
index = 2;
|
index = 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case ESysProxyType.Unchanged:
|
||||||
index = 3;
|
index = 3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -77,7 +78,7 @@ namespace v2rayN.Handler
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var item = ConfigHandler.GetDefaultRouting(ref config);
|
var item = ConfigHandler.GetDefaultRouting(config);
|
||||||
if (item == null || Utils.IsNullOrEmpty(item.customIcon) || !File.Exists(item.customIcon))
|
if (item == null || Utils.IsNullOrEmpty(item.customIcon) || !File.Exists(item.customIcon))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@@ -112,7 +113,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,7 +126,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
if (item.configType == EConfigType.Custom)
|
if (item.configType == EConfigType.Custom)
|
||||||
{
|
{
|
||||||
UI.Show(ResUI.NonVmessService);
|
Locator.Current.GetService<NoticeHandler>()?.Enqueue(ResUI.NonVmessService);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,147 +145,27 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//Config configCopy = Utils.DeepCopy(config);
|
if (CoreConfigHandler.GenerateClientConfig(item, fileName, out string msg, out string content) != 0)
|
||||||
//configCopy.index = index;
|
|
||||||
if (CoreConfigHandler.Export2ClientConfig(item, fileName, out string msg) != 0)
|
|
||||||
{
|
{
|
||||||
UI.Show(msg);
|
Locator.Current.GetService<NoticeHandler>()?.Enqueue(msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UI.ShowWarning(string.Format(ResUI.SaveClientConfigurationIn, fileName));
|
msg = string.Format(ResUI.SaveClientConfigurationIn, fileName);
|
||||||
|
Locator.Current.GetService<NoticeHandler>()?.SendMessageAndEnqueue(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Export2ServerConfig(ProfileItem item, Config config)
|
|
||||||
{
|
|
||||||
if (item == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (item.configType is not EConfigType.VMess and not EConfigType.VLESS)
|
|
||||||
{
|
|
||||||
UI.Show(ResUI.NonVmessService);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveFileDialog fileDialog = new()
|
|
||||||
{
|
|
||||||
Filter = "Config|*.json",
|
|
||||||
FilterIndex = 2,
|
|
||||||
RestoreDirectory = true
|
|
||||||
};
|
|
||||||
if (fileDialog.ShowDialog() != true)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
string fileName = fileDialog.FileName;
|
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//Config configCopy = Utils.DeepCopy(config);
|
|
||||||
//configCopy.index = index;
|
|
||||||
if (CoreConfigHandler.Export2ServerConfig(item, fileName, out string msg) != 0)
|
|
||||||
{
|
|
||||||
UI.Show(msg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UI.ShowWarning(string.Format(ResUI.SaveServerConfigurationIn, fileName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BackupGuiNConfig(Config config, bool auto = false)
|
|
||||||
{
|
|
||||||
string fileName = $"guiNConfig_{DateTime.Now:yyyy_MM_dd_HH_mm_ss_fff}.json";
|
|
||||||
if (auto)
|
|
||||||
{
|
|
||||||
fileName = Utils.GetBackupPath(fileName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SaveFileDialog fileDialog = new()
|
|
||||||
{
|
|
||||||
FileName = fileName,
|
|
||||||
Filter = "guiNConfig|*.json",
|
|
||||||
FilterIndex = 2,
|
|
||||||
RestoreDirectory = true
|
|
||||||
};
|
|
||||||
if (fileDialog.ShowDialog() != true)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fileName = fileDialog.FileName;
|
|
||||||
}
|
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var ret = Utils.ToJsonFile(config, fileName);
|
|
||||||
if (!auto)
|
|
||||||
{
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
|
||||||
UI.Show(ResUI.OperationSuccess);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UI.ShowWarning(ResUI.OperationFailed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool RestoreGuiNConfig(ref Config config)
|
|
||||||
{
|
|
||||||
var fileContent = string.Empty;
|
|
||||||
OpenFileDialog fileDialog = new();
|
|
||||||
|
|
||||||
fileDialog.InitialDirectory = Utils.GetBackupPath("");
|
|
||||||
fileDialog.Filter = "guiNConfig|*.json|All|*.*";
|
|
||||||
fileDialog.FilterIndex = 2;
|
|
||||||
fileDialog.RestoreDirectory = true;
|
|
||||||
|
|
||||||
if (fileDialog.ShowDialog() == true)
|
|
||||||
{
|
|
||||||
fileContent = Utils.LoadResource(fileDialog.FileName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Utils.IsNullOrEmpty(fileContent))
|
|
||||||
{
|
|
||||||
UI.ShowWarning(ResUI.OperationFailed);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var resConfig = Utils.FromJson<Config>(fileContent);
|
|
||||||
if (resConfig == null)
|
|
||||||
{
|
|
||||||
UI.ShowWarning(ResUI.OperationFailed);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//backup first
|
|
||||||
BackupGuiNConfig(config, true);
|
|
||||||
|
|
||||||
config = resConfig;
|
|
||||||
LazyConfig.Instance.SetConfig(config);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateTask(Config config, Action<bool, string> update)
|
public void UpdateTask(Config config, Action<bool, string> update)
|
||||||
{
|
{
|
||||||
Task.Run(() => UpdateTaskRunSubscription(config, update));
|
Task.Run(() => UpdateTaskRunSubscription(config, update));
|
||||||
Task.Run(() => UpdateTaskRunGeo(config, update));
|
Task.Run(() => UpdateTaskRunGeo(config, update));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateTaskRunSubscription(Config config, Action<bool, string> update)
|
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> update)
|
||||||
{
|
{
|
||||||
Thread.Sleep(60000);
|
await Task.Delay(60000);
|
||||||
Utils.SaveLog("UpdateTaskRunSubscription");
|
Logging.SaveLog("UpdateTaskRunSubscription");
|
||||||
|
|
||||||
var updateHandle = new UpdateHandle();
|
var updateHandle = new UpdateHandle();
|
||||||
while (true)
|
while (true)
|
||||||
@@ -301,23 +182,23 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
update(success, msg);
|
update(success, msg);
|
||||||
if (success)
|
if (success)
|
||||||
Utils.SaveLog("subscription" + msg);
|
Logging.SaveLog("subscription" + msg);
|
||||||
});
|
});
|
||||||
item.updateTime = updateTime;
|
item.updateTime = updateTime;
|
||||||
ConfigHandler.AddSubItem(ref config, item);
|
ConfigHandler.AddSubItem(config, item);
|
||||||
|
|
||||||
Thread.Sleep(5000);
|
await Task.Delay(5000);
|
||||||
}
|
}
|
||||||
Thread.Sleep(60000);
|
await Task.Delay(60000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateTaskRunGeo(Config config, Action<bool, string> update)
|
private async Task UpdateTaskRunGeo(Config config, Action<bool, string> update)
|
||||||
{
|
{
|
||||||
var autoUpdateGeoTime = DateTime.Now;
|
var autoUpdateGeoTime = DateTime.Now;
|
||||||
|
|
||||||
Thread.Sleep(1000 * 120);
|
await Task.Delay(1000 * 120);
|
||||||
Utils.SaveLog("UpdateTaskRunGeo");
|
Logging.SaveLog("UpdateTaskRunGeo");
|
||||||
|
|
||||||
var updateHandle = new UpdateHandle();
|
var updateHandle = new UpdateHandle();
|
||||||
while (true)
|
while (true)
|
||||||
@@ -327,24 +208,15 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0)
|
if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0)
|
||||||
{
|
{
|
||||||
updateHandle.UpdateGeoFile("geosite", config, (bool success, string msg) =>
|
updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
|
||||||
{
|
{
|
||||||
update(false, msg);
|
update(false, msg);
|
||||||
if (success)
|
|
||||||
Utils.SaveLog("geosite" + msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
updateHandle.UpdateGeoFile("geoip", config, (bool success, string msg) =>
|
|
||||||
{
|
|
||||||
update(false, msg);
|
|
||||||
if (success)
|
|
||||||
Utils.SaveLog("geoip" + msg);
|
|
||||||
});
|
});
|
||||||
autoUpdateGeoTime = dtNow;
|
autoUpdateGeoTime = dtNow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread.Sleep(1000 * 3600);
|
await Task.Delay(1000 * 3600);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,24 +10,32 @@ namespace v2rayN.Handler
|
|||||||
public NoticeHandler(ISnackbarMessageQueue snackbarMessageQueue)
|
public NoticeHandler(ISnackbarMessageQueue snackbarMessageQueue)
|
||||||
{
|
{
|
||||||
_snackbarMessageQueue = snackbarMessageQueue ?? throw new ArgumentNullException(nameof(snackbarMessageQueue));
|
_snackbarMessageQueue = snackbarMessageQueue ?? throw new ArgumentNullException(nameof(snackbarMessageQueue));
|
||||||
|
|
||||||
//_snackbarMessageQueue = snackbarMessageQueue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Enqueue(object content)
|
public void Enqueue(string content)
|
||||||
{
|
{
|
||||||
|
if (content.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
_snackbarMessageQueue?.Enqueue(content);
|
_snackbarMessageQueue?.Enqueue(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessage(string msg)
|
public void SendMessage(string msg)
|
||||||
{
|
{
|
||||||
MessageBus.Current.SendMessage(msg, "MsgView");
|
MessageBus.Current.SendMessage(msg, Global.CommandSendMsgView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessage(string msg, bool time)
|
public void SendMessage(string msg, bool time)
|
||||||
{
|
{
|
||||||
msg = $"{DateTime.Now} {msg}";
|
msg = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} {msg}";
|
||||||
MessageBus.Current.SendMessage(msg, "MsgView");
|
SendMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendMessageAndEnqueue(string msg)
|
||||||
|
{
|
||||||
|
Enqueue(msg);
|
||||||
|
SendMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using v2rayN.Base;
|
using v2rayN.Models;
|
||||||
using v2rayN.Mode;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
internal class ProfileExHandler
|
internal class ProfileExHandler
|
||||||
{
|
{
|
||||||
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
|
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
|
||||||
private ConcurrentBag<ProfileExItem> _lstProfileEx;
|
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
|
||||||
private Queue<string> _queIndexIds = new();
|
private Queue<string> _queIndexIds = new();
|
||||||
public ConcurrentBag<ProfileExItem> ProfileExs => _lstProfileEx;
|
public ConcurrentBag<ProfileExItem> ProfileExs => _lstProfileEx;
|
||||||
public static ProfileExHandler Instance => _instance.Value;
|
public static ProfileExHandler Instance => _instance.Value;
|
||||||
@@ -16,31 +15,22 @@ namespace v2rayN.Handler
|
|||||||
public ProfileExHandler()
|
public ProfileExHandler()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
|
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
SaveQueueIndexIds();
|
||||||
|
await Task.Delay(1000 * 600);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Init()
|
private void Init()
|
||||||
{
|
{
|
||||||
SqliteHelper.Instance.Execute($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
|
SQLiteHelper.Instance.Execute($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
|
||||||
|
|
||||||
_lstProfileEx = new(SqliteHelper.Instance.Table<ProfileExItem>());
|
_lstProfileEx = new(SQLiteHelper.Instance.Table<ProfileExItem>());
|
||||||
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var cnt = _queIndexIds.Count;
|
|
||||||
for (int i = 0; i < cnt; i++)
|
|
||||||
{
|
|
||||||
var id = _queIndexIds.Dequeue();
|
|
||||||
var item = _lstProfileEx.FirstOrDefault(t => t.indexId == id);
|
|
||||||
if (item is not null)
|
|
||||||
{
|
|
||||||
SqliteHelper.Instance.Replace(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Thread.Sleep(1000 * 60);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void IndexIdEnqueue(string indexId)
|
private void IndexIdEnqueue(string indexId)
|
||||||
@@ -51,7 +41,50 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddProfileEx(string indexId, ref ProfileExItem profileEx)
|
private void SaveQueueIndexIds()
|
||||||
|
{
|
||||||
|
var cnt = _queIndexIds.Count;
|
||||||
|
if (cnt > 0)
|
||||||
|
{
|
||||||
|
var lstExists = SQLiteHelper.Instance.Table<ProfileExItem>();
|
||||||
|
List<ProfileExItem> lstInserts = [];
|
||||||
|
List<ProfileExItem> lstUpdates = [];
|
||||||
|
|
||||||
|
for (int i = 0; i < cnt; i++)
|
||||||
|
{
|
||||||
|
var id = _queIndexIds.Dequeue();
|
||||||
|
var item = lstExists.FirstOrDefault(t => t.indexId == id);
|
||||||
|
var itemNew = _lstProfileEx?.FirstOrDefault(t => t.indexId == id);
|
||||||
|
if (itemNew is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item is not null)
|
||||||
|
{
|
||||||
|
lstUpdates.Add(itemNew);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lstInserts.Add(itemNew);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (lstInserts.Count() > 0)
|
||||||
|
SQLiteHelper.Instance.InsertAll(lstInserts);
|
||||||
|
|
||||||
|
if (lstUpdates.Count() > 0)
|
||||||
|
SQLiteHelper.Instance.UpdateAll(lstUpdates);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("ProfileExHandler", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddProfileEx(string indexId, ref ProfileExItem? profileEx)
|
||||||
{
|
{
|
||||||
profileEx = new()
|
profileEx = new()
|
||||||
{
|
{
|
||||||
@@ -66,7 +99,7 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
public void ClearAll()
|
public void ClearAll()
|
||||||
{
|
{
|
||||||
SqliteHelper.Instance.Execute($"delete from ProfileExItem ");
|
SQLiteHelper.Instance.Execute($"delete from ProfileExItem ");
|
||||||
_lstProfileEx = new();
|
_lstProfileEx = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,15 +107,11 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//foreach (var item in _lstProfileEx)
|
SaveQueueIndexIds();
|
||||||
//{
|
|
||||||
// SqliteHelper.Instance.Replace(item);
|
|
||||||
//}
|
|
||||||
SqliteHelper.Instance.UpdateAll(_lstProfileEx);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,43 +1,73 @@
|
|||||||
using Microsoft.Win32;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.InteropServices;
|
using static v2rayN.Handler.ProxySetting.InternetConnectionOption;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
internal class ProxySetting
|
internal class ProxySetting
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
// set to use no proxy
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
|
||||||
public static bool UnsetProxy()
|
public static bool UnsetProxy()
|
||||||
{
|
{
|
||||||
return SetProxy(null, null, 1);
|
return SetProxy(null, null, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set system proxy settings
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="strProxy"> proxy address</param>
|
||||||
|
/// <param name="exceptions">exception addresses that do not use proxy</param>
|
||||||
|
/// <param name="type">type of proxy defined in PerConnFlags
|
||||||
|
/// PROXY_TYPE_DIRECT = 0x00000001, // direct connection (no proxy)
|
||||||
|
/// PROXY_TYPE_PROXY = 0x00000002, // via named proxy
|
||||||
|
/// PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy script URL
|
||||||
|
/// PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
|
||||||
|
/// </param>
|
||||||
|
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
|
||||||
|
/// <returns>true: one of connection is successfully updated proxy settings</returns>
|
||||||
public static bool SetProxy(string? strProxy, string? exceptions, int type)
|
public static bool SetProxy(string? strProxy, string? exceptions, int type)
|
||||||
|
{
|
||||||
|
// set proxy for LAN
|
||||||
|
bool result = SetConnectionProxy(null, strProxy, exceptions, type);
|
||||||
|
// set proxy for dial up connections
|
||||||
|
var connections = EnumerateRasEntries();
|
||||||
|
foreach (var connection in connections)
|
||||||
|
{
|
||||||
|
result |= SetConnectionProxy(connection, strProxy, exceptions, type);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool SetConnectionProxy(string? connectionName, string? strProxy, string? exceptions, int type)
|
||||||
{
|
{
|
||||||
InternetPerConnOptionList list = new();
|
InternetPerConnOptionList list = new();
|
||||||
|
|
||||||
int optionCount = 1;
|
int optionCount = 1;
|
||||||
if (type == 1)
|
if (type == 1) // No proxy
|
||||||
{
|
{
|
||||||
optionCount = 1;
|
optionCount = 1;
|
||||||
}
|
}
|
||||||
else if (type is 2 or 4)
|
else if (type is 2 or 4) // named proxy or autoproxy script URL
|
||||||
{
|
{
|
||||||
optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3;
|
optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
int m_Int = (int)PerConnFlags.PROXY_TYPE_DIRECT;
|
int m_Int = (int)PerConnFlags.PROXY_TYPE_DIRECT;
|
||||||
PerConnOption m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
|
PerConnOption m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
|
||||||
if (type == 2)
|
if (type == 2) // named proxy
|
||||||
{
|
{
|
||||||
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY);
|
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY);
|
||||||
m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_SERVER;
|
m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_SERVER;
|
||||||
}
|
}
|
||||||
else if (type == 4)
|
else if (type == 4) // autoproxy script url
|
||||||
{
|
{
|
||||||
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL);
|
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL);
|
||||||
m_Option = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL;
|
m_Option = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//int optionCount = Utils.IsNullOrEmpty(strProxy) ? 1 : (Utils.IsNullOrEmpty(exceptions) ? 2 : 3);
|
//int optionCount = Utile.IsNullOrEmpty(strProxy) ? 1 : (Utile.IsNullOrEmpty(exceptions) ? 2 : 3);
|
||||||
InternetConnectionOption[] options = new InternetConnectionOption[optionCount];
|
InternetConnectionOption[] options = new InternetConnectionOption[optionCount];
|
||||||
// USE a proxy server ...
|
// USE a proxy server ...
|
||||||
options[0].m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
|
options[0].m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
|
||||||
@@ -47,24 +77,31 @@ namespace v2rayN.Handler
|
|||||||
if (optionCount > 1)
|
if (optionCount > 1)
|
||||||
{
|
{
|
||||||
options[1].m_Option = m_Option;
|
options[1].m_Option = m_Option;
|
||||||
options[1].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(strProxy);
|
options[1].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(strProxy); // !! remember to deallocate memory 1
|
||||||
// except for these addresses ...
|
// except for these addresses ...
|
||||||
if (optionCount > 2)
|
if (optionCount > 2)
|
||||||
{
|
{
|
||||||
options[2].m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_BYPASS;
|
options[2].m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_BYPASS;
|
||||||
options[2].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(exceptions);
|
options[2].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(exceptions); // !! remember to deallocate memory 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// default stuff
|
// default stuff
|
||||||
list.dwSize = Marshal.SizeOf(list);
|
list.dwSize = Marshal.SizeOf(list);
|
||||||
list.szConnection = IntPtr.Zero;
|
if (connectionName != null)
|
||||||
|
{
|
||||||
|
list.szConnection = Marshal.StringToHGlobalAuto(connectionName); // !! remember to deallocate memory 3
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list.szConnection = IntPtr.Zero;
|
||||||
|
}
|
||||||
list.dwOptionCount = options.Length;
|
list.dwOptionCount = options.Length;
|
||||||
list.dwOptionError = 0;
|
list.dwOptionError = 0;
|
||||||
|
|
||||||
int optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
|
int optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
|
||||||
// make a pointer out of all that ...
|
// make a pointer out of all that ...
|
||||||
IntPtr optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length);
|
IntPtr optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
|
||||||
// copy the array over into that spot in memory ...
|
// copy the array over into that spot in memory ...
|
||||||
for (int i = 0; i < options.Length; ++i)
|
for (int i = 0; i < options.Length; ++i)
|
||||||
{
|
{
|
||||||
@@ -83,26 +120,82 @@ namespace v2rayN.Handler
|
|||||||
list.options = optionsPtr;
|
list.options = optionsPtr;
|
||||||
|
|
||||||
// and then make a pointer out of the whole list
|
// and then make a pointer out of the whole list
|
||||||
IntPtr ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize);
|
IntPtr ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); // !! remember to deallocate memory 5
|
||||||
Marshal.StructureToPtr(list, ipcoListPtr, false);
|
Marshal.StructureToPtr(list, ipcoListPtr, false);
|
||||||
|
|
||||||
// and finally, call the API method!
|
// and finally, call the API method!
|
||||||
int returnvalue = NativeMethods.InternetSetOption(IntPtr.Zero,
|
bool isSuccess = NativeMethods.InternetSetOption(IntPtr.Zero,
|
||||||
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
|
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
|
||||||
ipcoListPtr, list.dwSize) ? -1 : 0;
|
ipcoListPtr, list.dwSize);
|
||||||
if (returnvalue == 0)
|
int returnvalue = 0; // ERROR_SUCCESS
|
||||||
|
if (!isSuccess)
|
||||||
{ // get the error codes, they might be helpful
|
{ // get the error codes, they might be helpful
|
||||||
returnvalue = Marshal.GetLastWin32Error();
|
returnvalue = Marshal.GetLastPInvokeError();
|
||||||
}
|
}
|
||||||
// FREE the data ASAP
|
else
|
||||||
Marshal.FreeCoTaskMem(optionsPtr);
|
{
|
||||||
Marshal.FreeCoTaskMem(ipcoListPtr);
|
// Notify the system that the registry settings have been changed and cause them to be refreshed
|
||||||
if (returnvalue > 0)
|
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
|
||||||
{ // throw the error codes, they might be helpful
|
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
|
||||||
//throw new Win32Exception(Marshal.GetLastWin32Error());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (returnvalue < 0);
|
// FREE the data ASAP
|
||||||
|
if (list.szConnection != IntPtr.Zero) Marshal.FreeHGlobal(list.szConnection); // release mem 3
|
||||||
|
if (optionCount > 1)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1
|
||||||
|
if (optionCount > 2)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(options[2].m_Value.m_StringPtr); // release mem 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Marshal.FreeCoTaskMem(optionsPtr); // release mem 4
|
||||||
|
Marshal.FreeCoTaskMem(ipcoListPtr); // release mem 5
|
||||||
|
if (returnvalue != 0)
|
||||||
|
{
|
||||||
|
// throw the error codes, they might be helpful
|
||||||
|
throw new ApplicationException($"Set Internet Proxy failed with error code: {Marshal.GetLastWin32Error()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve list of connections including LAN and WAN to support PPPoE connection
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A list of RAS connection names. May be empty list if no dial up connection.</returns>
|
||||||
|
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
|
||||||
|
private static IEnumerable<string> EnumerateRasEntries()
|
||||||
|
{
|
||||||
|
int entries = 0;
|
||||||
|
// attempt to query with 1 entry buffer
|
||||||
|
RASENTRYNAME[] rasEntryNames = new RASENTRYNAME[1];
|
||||||
|
int bufferSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
||||||
|
rasEntryNames[0].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
||||||
|
|
||||||
|
uint result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
|
||||||
|
// increase buffer if the buffer is not large enough
|
||||||
|
if (result == (uint)ErrorCode.ERROR_BUFFER_TOO_SMALL)
|
||||||
|
{
|
||||||
|
rasEntryNames = new RASENTRYNAME[bufferSize / Marshal.SizeOf(typeof(RASENTRYNAME))];
|
||||||
|
for (int i = 0; i < rasEntryNames.Length; i++)
|
||||||
|
{
|
||||||
|
rasEntryNames[i].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
|
||||||
|
}
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
var entryNames = new List<string>();
|
||||||
|
for (int i = 0; i < entries; i++)
|
||||||
|
{
|
||||||
|
entryNames.Add(rasEntryNames[i].szEntryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return entryNames;
|
||||||
|
}
|
||||||
|
throw new ApplicationException($"RasEnumEntries failed with error code: {result}");
|
||||||
}
|
}
|
||||||
|
|
||||||
#region WinInet structures
|
#region WinInet structures
|
||||||
@@ -145,6 +238,25 @@ namespace v2rayN.Handler
|
|||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
public IntPtr m_StringPtr;
|
public IntPtr m_StringPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||||
|
public struct RASENTRYNAME
|
||||||
|
{
|
||||||
|
public int dwSize;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName + 1)]
|
||||||
|
public string szEntryName;
|
||||||
|
|
||||||
|
public int dwFlags;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 1)]
|
||||||
|
public string szPhonebookPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
public const int RAS_MaxEntryName = 256;
|
||||||
|
|
||||||
|
public const int MAX_PATH = 260; // Standard MAX_PATH value in Windows
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion WinInet structures
|
#endregion WinInet structures
|
||||||
@@ -156,7 +268,9 @@ namespace v2rayN.Handler
|
|||||||
//
|
//
|
||||||
public enum InternetOption : uint
|
public enum InternetOption : uint
|
||||||
{
|
{
|
||||||
INTERNET_OPTION_PER_CONNECTION_OPTION = 75
|
INTERNET_OPTION_PER_CONNECTION_OPTION = 75,
|
||||||
|
INTERNET_OPTION_REFRESH = 37,
|
||||||
|
INTERNET_OPTION_SETTINGS_CHANGED = 39
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -182,6 +296,12 @@ namespace v2rayN.Handler
|
|||||||
PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
|
PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ErrorCode : uint
|
||||||
|
{
|
||||||
|
ERROR_BUFFER_TOO_SMALL = 603,
|
||||||
|
ERROR_INVALID_SIZE = 632
|
||||||
|
}
|
||||||
|
|
||||||
#endregion WinInet enums
|
#endregion WinInet enums
|
||||||
|
|
||||||
internal static class NativeMethods
|
internal static class NativeMethods
|
||||||
@@ -189,28 +309,15 @@ namespace v2rayN.Handler
|
|||||||
[DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
[DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
public static extern bool InternetSetOption(IntPtr hInternet, InternetOption dwOption, IntPtr lpBuffer, int dwBufferLength);
|
public static extern bool InternetSetOption(IntPtr hInternet, InternetOption dwOption, IntPtr lpBuffer, int dwBufferLength);
|
||||||
}
|
|
||||||
|
|
||||||
//判断是否使用代理
|
[DllImport("Rasapi32.dll", CharSet = CharSet.Auto)]
|
||||||
public static bool UsedProxy()
|
public static extern uint RasEnumEntries(
|
||||||
{
|
string? reserved, // Reserved, must be null
|
||||||
using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
|
string? lpszPhonebook, // Pointer to full path and filename of phone-book file. If this parameter is NULL, the entries are enumerated from all the remote access phone-book files
|
||||||
if (rk?.GetValue("ProxyEnable")?.ToString() == "1")
|
[In, Out] RASENTRYNAME[]? lprasentryname, // Buffer to receive RAS entry names
|
||||||
{
|
ref int lpcb, // Size of the buffer
|
||||||
return true;
|
ref int lpcEntries // Number of entries written to the buffer
|
||||||
}
|
);
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//获得代理的IP和端口
|
|
||||||
public static string? GetProxyProxyServer()
|
|
||||||
{
|
|
||||||
using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
|
|
||||||
string ProxyServer = rk.GetValue("ProxyServer").ToString();
|
|
||||||
return ProxyServer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
using QRCoder;
|
|
||||||
using QRCoder.Xaml;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 含有QR码的描述类和包装编码和渲染
|
|
||||||
/// </summary>
|
|
||||||
public class QRCodeHelper
|
|
||||||
{
|
|
||||||
public static DrawingImage? GetQRCode(string strContent)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
QRCodeGenerator qrGenerator = new();
|
|
||||||
QRCodeData qrCodeData = qrGenerator.CreateQrCode(strContent, QRCodeGenerator.ECCLevel.H);
|
|
||||||
XamlQRCode qrCode = new(qrCodeData);
|
|
||||||
DrawingImage qrCodeAsXaml = qrCode.GetGraphic(40);
|
|
||||||
return qrCodeAsXaml;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Web;
|
using v2rayN.Models;
|
||||||
using v2rayN.Base;
|
|
||||||
using v2rayN.Mode;
|
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
@@ -29,6 +27,9 @@ namespace v2rayN.Handler
|
|||||||
EConfigType.Socks => ShareSocks(item),
|
EConfigType.Socks => ShareSocks(item),
|
||||||
EConfigType.Trojan => ShareTrojan(item),
|
EConfigType.Trojan => ShareTrojan(item),
|
||||||
EConfigType.VLESS => ShareVLESS(item),
|
EConfigType.VLESS => ShareVLESS(item),
|
||||||
|
EConfigType.Hysteria2 => ShareHysteria2(item),
|
||||||
|
EConfigType.Tuic => ShareTuic(item),
|
||||||
|
EConfigType.Wireguard => ShareWireguard(item),
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,12 +48,12 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
VmessQRCode vmessQRCode = new()
|
VmessQRCode vmessQRCode = new()
|
||||||
{
|
{
|
||||||
v = item.configVersion.ToString(),
|
v = item.configVersion,
|
||||||
ps = item.remarks.TrimEx(),
|
ps = item.remarks.TrimEx(),
|
||||||
add = item.address,
|
add = item.address,
|
||||||
port = item.port.ToString(),
|
port = item.port,
|
||||||
id = item.id,
|
id = item.id,
|
||||||
aid = item.alterId.ToString(),
|
aid = item.alterId,
|
||||||
scy = item.security,
|
scy = item.security,
|
||||||
net = item.network,
|
net = item.network,
|
||||||
type = item.headerType,
|
type = item.headerType,
|
||||||
@@ -64,9 +65,9 @@ namespace v2rayN.Handler
|
|||||||
fp = item.fingerprint
|
fp = item.fingerprint
|
||||||
};
|
};
|
||||||
|
|
||||||
url = Utils.ToJson(vmessQRCode);
|
url = JsonUtils.Serialize(vmessQRCode);
|
||||||
url = Utils.Base64Encode(url);
|
url = Utils.Base64Encode(url);
|
||||||
url = $"{Global.vmessProtocol}{url}";
|
url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}";
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
@@ -85,11 +86,11 @@ namespace v2rayN.Handler
|
|||||||
// item.id,
|
// item.id,
|
||||||
// item.address,
|
// item.address,
|
||||||
// item.port);
|
// item.port);
|
||||||
//url = Utils.Base64Encode(url);
|
//url = Utile.Base64Encode(url);
|
||||||
//new Sip002
|
//new Sip002
|
||||||
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
||||||
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
||||||
url = $"{Global.ssProtocol}{url}{remark}";
|
url = $"{Global.ProtocolShares[EConfigType.Shadowsocks]}{url}{remark}";
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,11 +107,11 @@ namespace v2rayN.Handler
|
|||||||
// item.id,
|
// item.id,
|
||||||
// item.address,
|
// item.address,
|
||||||
// item.port);
|
// item.port);
|
||||||
//url = Utils.Base64Encode(url);
|
//url = Utile.Base64Encode(url);
|
||||||
//new
|
//new
|
||||||
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
||||||
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
||||||
url = $"{Global.socksProtocol}{url}{remark}";
|
url = $"{Global.ProtocolShares[EConfigType.Socks]}{url}{remark}";
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +131,7 @@ namespace v2rayN.Handler
|
|||||||
item.id,
|
item.id,
|
||||||
GetIpv6(item.address),
|
GetIpv6(item.address),
|
||||||
item.port);
|
item.port);
|
||||||
url = $"{Global.trojanProtocol}{url}{query}{remark}";
|
url = $"{Global.ProtocolShares[EConfigType.Trojan]}{url}{query}{remark}";
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,22 +150,126 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dicQuery.Add("encryption", "none");
|
dicQuery.Add("encryption", Global.None);
|
||||||
}
|
}
|
||||||
GetStdTransport(item, "none", ref dicQuery);
|
GetStdTransport(item, Global.None, ref dicQuery);
|
||||||
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||||
|
|
||||||
url = string.Format("{0}@{1}:{2}",
|
url = string.Format("{0}@{1}:{2}",
|
||||||
item.id,
|
item.id,
|
||||||
GetIpv6(item.address),
|
GetIpv6(item.address),
|
||||||
item.port);
|
item.port);
|
||||||
url = $"{Global.vlessProtocol}{url}{query}{remark}";
|
url = $"{Global.ProtocolShares[EConfigType.VLESS]}{url}{query}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ShareHysteria2(ProfileItem item)
|
||||||
|
{
|
||||||
|
string url = string.Empty;
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
var dicQuery = new Dictionary<string, string>();
|
||||||
|
if (!Utils.IsNullOrEmpty(item.sni))
|
||||||
|
{
|
||||||
|
dicQuery.Add("sni", item.sni);
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.alpn))
|
||||||
|
{
|
||||||
|
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
|
{
|
||||||
|
dicQuery.Add("obfs", "salamander");
|
||||||
|
dicQuery.Add("obfs-password", Utils.UrlEncode(item.path));
|
||||||
|
}
|
||||||
|
dicQuery.Add("insecure", item.allowInsecure.ToLower() == "true" ? "1" : "0");
|
||||||
|
|
||||||
|
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||||
|
|
||||||
|
url = string.Format("{0}@{1}:{2}",
|
||||||
|
item.id,
|
||||||
|
GetIpv6(item.address),
|
||||||
|
item.port);
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.Hysteria2]}{url}/{query}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ShareTuic(ProfileItem item)
|
||||||
|
{
|
||||||
|
string url = string.Empty;
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
var dicQuery = new Dictionary<string, string>();
|
||||||
|
if (!Utils.IsNullOrEmpty(item.sni))
|
||||||
|
{
|
||||||
|
dicQuery.Add("sni", item.sni);
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.alpn))
|
||||||
|
{
|
||||||
|
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||||
|
}
|
||||||
|
dicQuery.Add("congestion_control", item.headerType);
|
||||||
|
|
||||||
|
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||||
|
|
||||||
|
url = string.Format("{0}@{1}:{2}",
|
||||||
|
$"{item.id}:{item.security}",
|
||||||
|
GetIpv6(item.address),
|
||||||
|
item.port);
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.Tuic]}{url}{query}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ShareWireguard(ProfileItem item)
|
||||||
|
{
|
||||||
|
string url = string.Empty;
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
|
||||||
|
var dicQuery = new Dictionary<string, string>();
|
||||||
|
if (!Utils.IsNullOrEmpty(item.publicKey))
|
||||||
|
{
|
||||||
|
dicQuery.Add("publickey", Utils.UrlEncode(item.publicKey));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
|
{
|
||||||
|
dicQuery.Add("reserved", Utils.UrlEncode(item.path));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||||
|
{
|
||||||
|
dicQuery.Add("address", Utils.UrlEncode(item.requestHost));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.shortId))
|
||||||
|
{
|
||||||
|
dicQuery.Add("mtu", Utils.UrlEncode(item.shortId));
|
||||||
|
}
|
||||||
|
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
|
||||||
|
|
||||||
|
url = string.Format("{0}@{1}:{2}",
|
||||||
|
Utils.UrlEncode(item.id),
|
||||||
|
GetIpv6(item.address),
|
||||||
|
item.port);
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.Wireguard]}{url}/{query}{remark}";
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetIpv6(string address)
|
private static string GetIpv6(string address)
|
||||||
{
|
{
|
||||||
return Utils.IsIpv6(address) ? $"[{address}]" : address;
|
if (Utils.IsIpv6(address))
|
||||||
|
{
|
||||||
|
// 检查地址是否已经被方括号包围,如果没有,则添加方括号
|
||||||
|
return address.StartsWith('[') && address.EndsWith(']') ? address : $"[{address}]";
|
||||||
|
}
|
||||||
|
return address; // 如果不是IPv6地址,直接返回原地址
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
private static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
||||||
@@ -210,27 +315,28 @@ namespace v2rayN.Handler
|
|||||||
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
|
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
|
||||||
}
|
}
|
||||||
|
|
||||||
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : "tcp");
|
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : nameof(ETransport.tcp));
|
||||||
|
|
||||||
switch (item.network)
|
switch (item.network)
|
||||||
{
|
{
|
||||||
case "tcp":
|
case nameof(ETransport.tcp):
|
||||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : "none");
|
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||||
{
|
{
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "kcp":
|
case nameof(ETransport.kcp):
|
||||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : "none");
|
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||||
if (!Utils.IsNullOrEmpty(item.path))
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
{
|
{
|
||||||
dicQuery.Add("seed", Utils.UrlEncode(item.path));
|
dicQuery.Add("seed", Utils.UrlEncode(item.path));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "ws":
|
case nameof(ETransport.ws):
|
||||||
|
case nameof(ETransport.httpupgrade):
|
||||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||||
{
|
{
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||||
@@ -241,9 +347,9 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "http":
|
case nameof(ETransport.http):
|
||||||
case "h2":
|
case nameof(ETransport.h2):
|
||||||
dicQuery["type"] = "http";
|
dicQuery["type"] = nameof(ETransport.http);
|
||||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||||
{
|
{
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||||
@@ -254,17 +360,18 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "quic":
|
case nameof(ETransport.quic):
|
||||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : "none");
|
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||||
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost));
|
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost));
|
||||||
dicQuery.Add("key", Utils.UrlEncode(item.path));
|
dicQuery.Add("key", Utils.UrlEncode(item.path));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "grpc":
|
case nameof(ETransport.grpc):
|
||||||
if (!Utils.IsNullOrEmpty(item.path))
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
{
|
{
|
||||||
|
dicQuery.Add("authority", Utils.UrlEncode(item.requestHost));
|
||||||
dicQuery.Add("serviceName", Utils.UrlEncode(item.path));
|
dicQuery.Add("serviceName", Utils.UrlEncode(item.path));
|
||||||
if (item.headerType is Global.GrpcgunMode or Global.GrpcmultiMode)
|
if (item.headerType is Global.GrpcGunMode or Global.GrpcMultiMode)
|
||||||
{
|
{
|
||||||
dicQuery.Add("mode", Utils.UrlEncode(item.headerType));
|
dicQuery.Add("mode", Utils.UrlEncode(item.headerType));
|
||||||
}
|
}
|
||||||
@@ -285,21 +392,19 @@ namespace v2rayN.Handler
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static ProfileItem? ImportFromClipboardConfig(string clipboardData, out string msg)
|
public static ProfileItem? ImportFromClipboardConfig(string clipboardData, out string msg)
|
||||||
{
|
{
|
||||||
msg = string.Empty;
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
ProfileItem? profileItem;
|
||||||
ProfileItem profileItem = new();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//载入配置文件
|
string result = clipboardData.TrimEx();
|
||||||
string result = clipboardData.TrimEx();// Utils.GetClipboardData();
|
|
||||||
if (Utils.IsNullOrEmpty(result))
|
if (Utils.IsNullOrEmpty(result))
|
||||||
{
|
{
|
||||||
msg = ResUI.FailedReadConfiguration;
|
msg = ResUI.FailedReadConfiguration;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.StartsWith(Global.vmessProtocol))
|
if (result.StartsWith(Global.ProtocolShares[EConfigType.VMess]))
|
||||||
{
|
{
|
||||||
int indexSplit = result.IndexOf("?");
|
int indexSplit = result.IndexOf("?");
|
||||||
if (indexSplit > 0)
|
if (indexSplit > 0)
|
||||||
@@ -311,10 +416,8 @@ namespace v2rayN.Handler
|
|||||||
profileItem = ResolveVmess(result, out msg);
|
profileItem = ResolveVmess(result, out msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (result.StartsWith(Global.ssProtocol))
|
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Shadowsocks]))
|
||||||
{
|
{
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
|
||||||
|
|
||||||
profileItem = ResolveSSLegacy(result) ?? ResolveSip002(result);
|
profileItem = ResolveSSLegacy(result) ?? ResolveSip002(result);
|
||||||
if (profileItem == null)
|
if (profileItem == null)
|
||||||
{
|
{
|
||||||
@@ -327,10 +430,8 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
profileItem.configType = EConfigType.Shadowsocks;
|
profileItem.configType = EConfigType.Shadowsocks;
|
||||||
}
|
}
|
||||||
else if (result.StartsWith(Global.socksProtocol))
|
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Socks]))
|
||||||
{
|
{
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
|
||||||
|
|
||||||
profileItem = ResolveSocksNew(result) ?? ResolveSocks(result);
|
profileItem = ResolveSocksNew(result) ?? ResolveSocks(result);
|
||||||
if (profileItem == null)
|
if (profileItem == null)
|
||||||
{
|
{
|
||||||
@@ -343,16 +444,26 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
profileItem.configType = EConfigType.Socks;
|
profileItem.configType = EConfigType.Socks;
|
||||||
}
|
}
|
||||||
else if (result.StartsWith(Global.trojanProtocol))
|
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Trojan]))
|
||||||
{
|
{
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
|
||||||
|
|
||||||
profileItem = ResolveTrojan(result);
|
profileItem = ResolveTrojan(result);
|
||||||
}
|
}
|
||||||
else if (result.StartsWith(Global.vlessProtocol))
|
else if (result.StartsWith(Global.ProtocolShares[EConfigType.VLESS]))
|
||||||
{
|
{
|
||||||
profileItem = ResolveStdVLESS(result);
|
profileItem = ResolveStdVLESS(result);
|
||||||
}
|
}
|
||||||
|
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Hysteria2]) || result.StartsWith(Global.Hysteria2ProtocolShare))
|
||||||
|
{
|
||||||
|
profileItem = ResolveHysteria2(result);
|
||||||
|
}
|
||||||
|
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Tuic]))
|
||||||
|
{
|
||||||
|
profileItem = ResolveTuic(result);
|
||||||
|
}
|
||||||
|
else if (result.StartsWith(Global.ProtocolShares[EConfigType.Wireguard]))
|
||||||
|
{
|
||||||
|
profileItem = ResolveWireguard(result);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
msg = ResUI.NonvmessOrssProtocol;
|
msg = ResUI.NonvmessOrssProtocol;
|
||||||
@@ -361,7 +472,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
msg = ResUI.Incorrectconfiguration;
|
msg = ResUI.Incorrectconfiguration;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -377,11 +488,11 @@ namespace v2rayN.Handler
|
|||||||
configType = EConfigType.VMess
|
configType = EConfigType.VMess
|
||||||
};
|
};
|
||||||
|
|
||||||
result = result[Global.vmessProtocol.Length..];
|
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
||||||
result = Utils.Base64Decode(result);
|
result = Utils.Base64Decode(result);
|
||||||
|
|
||||||
//转成Json
|
//转成Json
|
||||||
VmessQRCode? vmessQRCode = Utils.FromJson<VmessQRCode>(result);
|
VmessQRCode? vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
|
||||||
if (vmessQRCode == null)
|
if (vmessQRCode == null)
|
||||||
{
|
{
|
||||||
msg = ResUI.FailedConversionConfiguration;
|
msg = ResUI.FailedConversionConfiguration;
|
||||||
@@ -425,7 +536,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
configType = EConfigType.VMess
|
configType = EConfigType.VMess
|
||||||
};
|
};
|
||||||
result = result[Global.vmessProtocol.Length..];
|
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
||||||
int indexSplit = result.IndexOf("?");
|
int indexSplit = result.IndexOf("?");
|
||||||
if (indexSplit > 0)
|
if (indexSplit > 0)
|
||||||
{
|
{
|
||||||
@@ -470,7 +581,7 @@ namespace v2rayN.Handler
|
|||||||
i.address = u.IdnHost;
|
i.address = u.IdnHost;
|
||||||
i.port = u.Port;
|
i.port = u.Port;
|
||||||
i.remarks = u.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
i.remarks = u.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
var q = HttpUtility.ParseQueryString(u.Query);
|
var query = Utils.ParseQueryString(u.Query);
|
||||||
|
|
||||||
var m = StdVmessUserInfo.Match(u.UserInfo);
|
var m = StdVmessUserInfo.Match(u.UserInfo);
|
||||||
if (!m.Success) return null;
|
if (!m.Success) return null;
|
||||||
@@ -483,12 +594,11 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
switch (i.streamSecurity)
|
switch (i.streamSecurity)
|
||||||
{
|
{
|
||||||
case "tls":
|
case Global.StreamSecurity:
|
||||||
// TODO tls config
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (!string.IsNullOrWhiteSpace(i.streamSecurity))
|
if (!Utils.IsNullOrEmpty(i.streamSecurity))
|
||||||
return null;
|
return null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -496,38 +606,36 @@ namespace v2rayN.Handler
|
|||||||
i.network = m.Groups["network"].Value;
|
i.network = m.Groups["network"].Value;
|
||||||
switch (i.network)
|
switch (i.network)
|
||||||
{
|
{
|
||||||
case "tcp":
|
case nameof(ETransport.tcp):
|
||||||
string t1 = q["type"] ?? "none";
|
string t1 = query["type"] ?? Global.None;
|
||||||
i.headerType = t1;
|
i.headerType = t1;
|
||||||
// TODO http option
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "kcp":
|
case nameof(ETransport.kcp):
|
||||||
i.headerType = q["type"] ?? "none";
|
i.headerType = query["type"] ?? Global.None;
|
||||||
// TODO kcp seed
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "ws":
|
case nameof(ETransport.ws):
|
||||||
string p1 = q["path"] ?? "/";
|
case nameof(ETransport.httpupgrade):
|
||||||
string h1 = q["host"] ?? "";
|
string p1 = query["path"] ?? "/";
|
||||||
|
string h1 = query["host"] ?? "";
|
||||||
i.requestHost = Utils.UrlDecode(h1);
|
i.requestHost = Utils.UrlDecode(h1);
|
||||||
i.path = p1;
|
i.path = p1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "http":
|
case nameof(ETransport.http):
|
||||||
case "h2":
|
case nameof(ETransport.h2):
|
||||||
i.network = "h2";
|
i.network = nameof(ETransport.h2);
|
||||||
string p2 = q["path"] ?? "/";
|
string p2 = query["path"] ?? "/";
|
||||||
string h2 = q["host"] ?? "";
|
string h2 = query["host"] ?? "";
|
||||||
i.requestHost = Utils.UrlDecode(h2);
|
i.requestHost = Utils.UrlDecode(h2);
|
||||||
i.path = p2;
|
i.path = p2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "quic":
|
case nameof(ETransport.quic):
|
||||||
string s = q["security"] ?? "none";
|
string s = query["security"] ?? Global.None;
|
||||||
string k = q["key"] ?? "";
|
string k = query["key"] ?? "";
|
||||||
string t3 = q["type"] ?? "none";
|
string t3 = query["type"] ?? Global.None;
|
||||||
i.headerType = t3;
|
i.headerType = t3;
|
||||||
i.requestHost = Utils.UrlDecode(s);
|
i.requestHost = Utils.UrlDecode(s);
|
||||||
i.path = k;
|
i.path = k;
|
||||||
@@ -582,17 +690,17 @@ namespace v2rayN.Handler
|
|||||||
server.id = userInfoParts[1];
|
server.id = userInfoParts[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
NameValueCollection queryParameters = HttpUtility.ParseQueryString(parsedUrl.Query);
|
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
|
||||||
if (queryParameters["plugin"] != null)
|
if (queryParameters["plugin"] != null)
|
||||||
{
|
{
|
||||||
//obfs-host exists
|
//obfs-host exists
|
||||||
var obfsHost = queryParameters["plugin"].Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
|
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
|
||||||
if (queryParameters["plugin"].Contains("obfs=http") && !Utils.IsNullOrEmpty(obfsHost))
|
if (queryParameters["plugin"].Contains("obfs=http") && !Utils.IsNullOrEmpty(obfsHost))
|
||||||
{
|
{
|
||||||
obfsHost = obfsHost.Replace("obfs-host=", "");
|
obfsHost = obfsHost?.Replace("obfs-host=", "");
|
||||||
server.network = Global.DefaultNetwork;
|
server.network = Global.DefaultNetwork;
|
||||||
server.headerType = Global.TcpHeaderHttp;
|
server.headerType = Global.TcpHeaderHttp;
|
||||||
server.requestHost = obfsHost;
|
server.requestHost = obfsHost ?? "";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -633,7 +741,7 @@ namespace v2rayN.Handler
|
|||||||
server.security = details.Groups["method"].Value;
|
server.security = details.Groups["method"].Value;
|
||||||
server.id = details.Groups["password"].Value;
|
server.id = details.Groups["password"].Value;
|
||||||
server.address = details.Groups["hostname"].Value;
|
server.address = details.Groups["hostname"].Value;
|
||||||
server.port = int.Parse(details.Groups["port"].Value);
|
server.port = Utils.ToInt(details.Groups["port"].Value);
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,7 +754,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
configType = EConfigType.Socks
|
configType = EConfigType.Socks
|
||||||
};
|
};
|
||||||
result = result[Global.socksProtocol.Length..];
|
result = result[Global.ProtocolShares[EConfigType.Socks].Length..];
|
||||||
//remark
|
//remark
|
||||||
int indexRemark = result.IndexOf("#");
|
int indexRemark = result.IndexOf("#");
|
||||||
if (indexRemark > 0)
|
if (indexRemark > 0)
|
||||||
@@ -731,9 +839,9 @@ namespace v2rayN.Handler
|
|||||||
item.address = url.IdnHost;
|
item.address = url.IdnHost;
|
||||||
item.port = url.Port;
|
item.port = url.Port;
|
||||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
item.id = url.UserInfo;
|
item.id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
var query = HttpUtility.ParseQueryString(url.Query);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
ResolveStdTransport(query, ref item);
|
ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
@@ -744,7 +852,7 @@ namespace v2rayN.Handler
|
|||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
configType = EConfigType.VLESS,
|
configType = EConfigType.VLESS,
|
||||||
security = "none"
|
security = Global.None
|
||||||
};
|
};
|
||||||
|
|
||||||
Uri url = new(result);
|
Uri url = new(result);
|
||||||
@@ -752,16 +860,88 @@ namespace v2rayN.Handler
|
|||||||
item.address = url.IdnHost;
|
item.address = url.IdnHost;
|
||||||
item.port = url.Port;
|
item.port = url.Port;
|
||||||
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
item.id = url.UserInfo;
|
item.id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
var query = HttpUtility.ParseQueryString(url.Query);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
item.security = query["encryption"] ?? "none";
|
item.security = query["encryption"] ?? Global.None;
|
||||||
item.streamSecurity = query["security"] ?? "";
|
item.streamSecurity = query["security"] ?? "";
|
||||||
ResolveStdTransport(query, ref item);
|
ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ProfileItem ResolveHysteria2(string result)
|
||||||
|
{
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Hysteria2
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(result);
|
||||||
|
|
||||||
|
item.address = url.IdnHost;
|
||||||
|
item.port = url.Port;
|
||||||
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
|
item.id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
|
ResolveStdTransport(query, ref item);
|
||||||
|
item.path = Utils.UrlDecode(query["obfs-password"] ?? "");
|
||||||
|
item.allowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProfileItem ResolveTuic(string result)
|
||||||
|
{
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Tuic
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(result);
|
||||||
|
|
||||||
|
item.address = url.IdnHost;
|
||||||
|
item.port = url.Port;
|
||||||
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
|
var userInfoParts = url.UserInfo.Split(new[] { ':' }, 2);
|
||||||
|
if (userInfoParts.Length == 2)
|
||||||
|
{
|
||||||
|
item.id = userInfoParts[0];
|
||||||
|
item.security = userInfoParts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
|
ResolveStdTransport(query, ref item);
|
||||||
|
item.headerType = query["congestion_control"] ?? "";
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProfileItem ResolveWireguard(string result)
|
||||||
|
{
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Wireguard
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(result);
|
||||||
|
|
||||||
|
item.address = url.IdnHost;
|
||||||
|
item.port = url.Port;
|
||||||
|
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
|
||||||
|
item.id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
|
|
||||||
|
item.publicKey = Utils.UrlDecode(query["publickey"] ?? "");
|
||||||
|
item.path = Utils.UrlDecode(query["reserved"] ?? "");
|
||||||
|
item.requestHost = Utils.UrlDecode(query["address"] ?? "");
|
||||||
|
item.shortId = Utils.UrlDecode(query["mtu"] ?? "");
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
private static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
|
private static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
|
||||||
{
|
{
|
||||||
item.flow = query["flow"] ?? "";
|
item.flow = query["flow"] ?? "";
|
||||||
@@ -773,41 +953,43 @@ namespace v2rayN.Handler
|
|||||||
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
|
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
|
||||||
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
|
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
|
||||||
|
|
||||||
item.network = query["type"] ?? "tcp";
|
item.network = query["type"] ?? nameof(ETransport.tcp);
|
||||||
switch (item.network)
|
switch (item.network)
|
||||||
{
|
{
|
||||||
case "tcp":
|
case nameof(ETransport.tcp):
|
||||||
item.headerType = query["headerType"] ?? "none";
|
item.headerType = query["headerType"] ?? Global.None;
|
||||||
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "kcp":
|
case nameof(ETransport.kcp):
|
||||||
item.headerType = query["headerType"] ?? "none";
|
item.headerType = query["headerType"] ?? Global.None;
|
||||||
item.path = Utils.UrlDecode(query["seed"] ?? "");
|
item.path = Utils.UrlDecode(query["seed"] ?? "");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "ws":
|
case nameof(ETransport.ws):
|
||||||
|
case nameof(ETransport.httpupgrade):
|
||||||
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "http":
|
case nameof(ETransport.http):
|
||||||
case "h2":
|
case nameof(ETransport.h2):
|
||||||
item.network = "h2";
|
item.network = nameof(ETransport.h2);
|
||||||
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "quic":
|
case nameof(ETransport.quic):
|
||||||
item.headerType = query["headerType"] ?? "none";
|
item.headerType = query["headerType"] ?? Global.None;
|
||||||
item.requestHost = query["quicSecurity"] ?? "none";
|
item.requestHost = query["quicSecurity"] ?? Global.None;
|
||||||
item.path = Utils.UrlDecode(query["key"] ?? "");
|
item.path = Utils.UrlDecode(query["key"] ?? "");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "grpc":
|
case nameof(ETransport.grpc):
|
||||||
|
item.requestHost = Utils.UrlDecode(query["authority"] ?? "");
|
||||||
item.path = Utils.UrlDecode(query["serviceName"] ?? "");
|
item.path = Utils.UrlDecode(query["serviceName"] ?? "");
|
||||||
item.headerType = Utils.UrlDecode(query["mode"] ?? Global.GrpcgunMode);
|
item.headerType = Utils.UrlDecode(query["mode"] ?? Global.GrpcGunMode);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
using System.Diagnostics;
|
using ReactiveUI;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using v2rayN.Mode;
|
using v2rayN.Models;
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
internal class SpeedtestHandler
|
internal class SpeedtestHandler
|
||||||
{
|
{
|
||||||
private Config _config;
|
private Config? _config;
|
||||||
private CoreHandler _coreHandler;
|
private CoreHandler _coreHandler;
|
||||||
private List<ServerTestItem> _selecteds;
|
private List<ServerTestItem> _selecteds;
|
||||||
private ESpeedActionType _actionType;
|
private ESpeedActionType _actionType;
|
||||||
@@ -51,7 +51,6 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
switch (actionType)
|
switch (actionType)
|
||||||
{
|
{
|
||||||
case ESpeedActionType.Ping:
|
|
||||||
case ESpeedActionType.Tcping:
|
case ESpeedActionType.Tcping:
|
||||||
case ESpeedActionType.Realping:
|
case ESpeedActionType.Realping:
|
||||||
UpdateFunc(it.indexId, ResUI.Speedtesting, "");
|
UpdateFunc(it.indexId, ResUI.Speedtesting, "");
|
||||||
@@ -73,10 +72,6 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
switch (actionType)
|
switch (actionType)
|
||||||
{
|
{
|
||||||
case ESpeedActionType.Ping:
|
|
||||||
Task.Run(RunPing);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ESpeedActionType.Tcping:
|
case ESpeedActionType.Tcping:
|
||||||
Task.Run(RunTcping);
|
Task.Run(RunTcping);
|
||||||
break;
|
break;
|
||||||
@@ -95,52 +90,45 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunPingSub(Action<ServerTestItem> updateFun)
|
private Task RunTcping()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (var it in _selecteds.Where(it => it.configType != EConfigType.Custom))
|
List<Task> tasks = [];
|
||||||
|
foreach (var it in _selecteds)
|
||||||
{
|
{
|
||||||
try
|
if (it.configType == EConfigType.Custom)
|
||||||
{
|
{
|
||||||
Task.Run(() => updateFun(it));
|
continue;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
tasks.Add(Task.Run(() =>
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
try
|
||||||
}
|
{
|
||||||
}
|
int time = GetTcpingTime(it.address, it.port);
|
||||||
|
var output = FormatOut(time, Global.DelayUnit);
|
||||||
|
|
||||||
Thread.Sleep(10);
|
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
||||||
|
UpdateFunc(it.indexId, output);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Task.WaitAll([.. tasks]);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
finally
|
||||||
|
|
||||||
private void RunPing()
|
|
||||||
{
|
|
||||||
RunPingSub((ServerTestItem it) =>
|
|
||||||
{
|
{
|
||||||
long time = Ping(it.address);
|
ProfileExHandler.Instance.SaveTo();
|
||||||
var output = FormatOut(time, Global.DelayUnit);
|
}
|
||||||
|
|
||||||
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
return Task.CompletedTask;
|
||||||
UpdateFunc(it.indexId, output);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RunTcping()
|
|
||||||
{
|
|
||||||
RunPingSub((ServerTestItem it) =>
|
|
||||||
{
|
|
||||||
int time = GetTcpingTime(it.address, it.port);
|
|
||||||
var output = FormatOut(time, Global.DelayUnit);
|
|
||||||
|
|
||||||
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
|
||||||
UpdateFunc(it.indexId, output);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task RunRealPing()
|
private Task RunRealPing()
|
||||||
@@ -150,7 +138,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
string msg = string.Empty;
|
string msg = string.Empty;
|
||||||
|
|
||||||
pid = _coreHandler.LoadCoreConfigString(_config, _selecteds);
|
pid = _coreHandler.LoadCoreConfigSpeedtest(_selecteds);
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
UpdateFunc("", ResUI.FailedToRunCore);
|
UpdateFunc("", ResUI.FailedToRunCore);
|
||||||
@@ -158,7 +146,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
DownloadHandle downloadHandle = new DownloadHandle();
|
DownloadHandle downloadHandle = new DownloadHandle();
|
||||||
//Thread.Sleep(5000);
|
|
||||||
List<Task> tasks = new();
|
List<Task> tasks = new();
|
||||||
foreach (var it in _selecteds)
|
foreach (var it in _selecteds)
|
||||||
{
|
{
|
||||||
@@ -170,12 +158,12 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tasks.Add(Task.Run(() =>
|
tasks.Add(Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
WebProxy webProxy = new(Global.Loopback, it.port);
|
WebProxy webProxy = new(Global.Loopback, it.port);
|
||||||
string output = GetRealPingTime(downloadHandle, webProxy);
|
string output = await GetRealPingTime(downloadHandle, webProxy);
|
||||||
|
|
||||||
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
||||||
UpdateFunc(it.indexId, output);
|
UpdateFunc(it.indexId, output);
|
||||||
@@ -184,20 +172,22 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
//Thread.Sleep(100);
|
|
||||||
}
|
}
|
||||||
Task.WaitAll(tasks.ToArray());
|
Task.WaitAll(tasks.ToArray());
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (pid > 0) _coreHandler.CoreStopPid(pid);
|
if (pid > 0)
|
||||||
|
{
|
||||||
|
_coreHandler.CoreStopPid(pid);
|
||||||
|
}
|
||||||
ProfileExHandler.Instance.SaveTo();
|
ProfileExHandler.Instance.SaveTo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +202,7 @@ namespace v2rayN.Handler
|
|||||||
// _selecteds = _selecteds.OrderBy(t => t.delay).ToList();
|
// _selecteds = _selecteds.OrderBy(t => t.delay).ToList();
|
||||||
//}
|
//}
|
||||||
|
|
||||||
pid = _coreHandler.LoadCoreConfigString(_config, _selecteds);
|
pid = _coreHandler.LoadCoreConfigSpeedtest(_selecteds);
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
UpdateFunc("", ResUI.FailedToRunCore);
|
UpdateFunc("", ResUI.FailedToRunCore);
|
||||||
@@ -224,8 +214,24 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
DownloadHandle downloadHandle = new();
|
DownloadHandle downloadHandle = new();
|
||||||
|
|
||||||
|
var exitLoop = false;
|
||||||
|
MessageBus.Current.Listen<string>(Global.CommandStopSpeedTest)
|
||||||
|
.Subscribe(x =>
|
||||||
|
{
|
||||||
|
if (!exitLoop)
|
||||||
|
{
|
||||||
|
UpdateFunc("", ResUI.SpeedtestingStop);
|
||||||
|
}
|
||||||
|
exitLoop = true;
|
||||||
|
});
|
||||||
|
|
||||||
foreach (var it in _selecteds)
|
foreach (var it in _selecteds)
|
||||||
{
|
{
|
||||||
|
if (exitLoop)
|
||||||
|
{
|
||||||
|
UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!it.allowTest)
|
if (!it.allowTest)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -269,7 +275,7 @@ namespace v2rayN.Handler
|
|||||||
private async Task RunSpeedTestMulti()
|
private async Task RunSpeedTestMulti()
|
||||||
{
|
{
|
||||||
int pid = -1;
|
int pid = -1;
|
||||||
pid = _coreHandler.LoadCoreConfigString(_config, _selecteds);
|
pid = _coreHandler.LoadCoreConfigSpeedtest(_selecteds);
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
UpdateFunc("", ResUI.FailedToRunCore);
|
UpdateFunc("", ResUI.FailedToRunCore);
|
||||||
@@ -281,8 +287,25 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
DownloadHandle downloadHandle = new();
|
DownloadHandle downloadHandle = new();
|
||||||
|
|
||||||
|
var exitLoop = false;
|
||||||
|
MessageBus.Current.Listen<string>(Global.CommandStopSpeedTest)
|
||||||
|
.Subscribe(x =>
|
||||||
|
{
|
||||||
|
if (!exitLoop)
|
||||||
|
{
|
||||||
|
UpdateFunc("", ResUI.SpeedtestingStop);
|
||||||
|
}
|
||||||
|
exitLoop = true;
|
||||||
|
});
|
||||||
|
|
||||||
foreach (var it in _selecteds)
|
foreach (var it in _selecteds)
|
||||||
{
|
{
|
||||||
|
if (exitLoop)
|
||||||
|
{
|
||||||
|
UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!it.allowTest)
|
if (!it.allowTest)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -312,10 +335,10 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
UpdateFunc(it.indexId, "", msg);
|
UpdateFunc(it.indexId, "", msg);
|
||||||
});
|
});
|
||||||
Thread.Sleep(2000);
|
await Task.Delay(2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread.Sleep((timeout + 2) * 1000);
|
await Task.Delay((timeout + 2) * 1000);
|
||||||
|
|
||||||
if (pid > 0)
|
if (pid > 0)
|
||||||
{
|
{
|
||||||
@@ -329,16 +352,16 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
await RunRealPing();
|
await RunRealPing();
|
||||||
|
|
||||||
Thread.Sleep(1000);
|
await Task.Delay(1000);
|
||||||
|
|
||||||
await RunSpeedTestMulti();
|
await RunSpeedTestMulti();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetRealPingTime(DownloadHandle downloadHandle, IWebProxy webProxy)
|
private async Task<string> GetRealPingTime(DownloadHandle downloadHandle, IWebProxy webProxy)
|
||||||
{
|
{
|
||||||
string status = downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10, out int responseTime);
|
int responseTime = await downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10);
|
||||||
//string output = Utils.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status;
|
//string output = Utile.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status;
|
||||||
return FormatOut(Utils.IsNullOrEmpty(status) ? responseTime : -1, Global.DelayUnit);
|
return FormatOut(responseTime, Global.DelayUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetTcpingTime(string url, int port)
|
private int GetTcpingTime(string url, int port)
|
||||||
@@ -347,7 +370,7 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!IPAddress.TryParse(url, out IPAddress ipAddress))
|
if (!IPAddress.TryParse(url, out IPAddress? ipAddress))
|
||||||
{
|
{
|
||||||
IPHostEntry ipHostInfo = System.Net.Dns.GetHostEntry(url);
|
IPHostEntry ipHostInfo = System.Net.Dns.GetHostEntry(url);
|
||||||
ipAddress = ipHostInfo.AddressList[0];
|
ipAddress = ipHostInfo.AddressList[0];
|
||||||
@@ -369,48 +392,11 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
return responseTime;
|
return responseTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ping
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="host"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public long Ping(string host)
|
|
||||||
{
|
|
||||||
long roundtripTime = -1;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int timeout = 30;
|
|
||||||
int echoNum = 2;
|
|
||||||
using Ping pingSender = new();
|
|
||||||
for (int i = 0; i < echoNum; i++)
|
|
||||||
{
|
|
||||||
PingReply reply = pingSender.Send(host, timeout);
|
|
||||||
if (reply.Status == IPStatus.Success)
|
|
||||||
{
|
|
||||||
if (reply.RoundtripTime < 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (roundtripTime < 0 || reply.RoundtripTime < roundtripTime)
|
|
||||||
{
|
|
||||||
roundtripTime = reply.RoundtripTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return roundtripTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string FormatOut(object time, string unit)
|
private string FormatOut(object time, string unit)
|
||||||
{
|
{
|
||||||
//if (time.ToString().Equals("-1"))
|
//if (time.ToString().Equals("-1"))
|
||||||
|
|||||||
@@ -1,121 +1,52 @@
|
|||||||
using Grpc.Core;
|
using v2rayN.Models;
|
||||||
using Grpc.Net.Client;
|
|
||||||
using ProtosLib.Statistics;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Sockets;
|
|
||||||
using v2rayN.Base;
|
|
||||||
using v2rayN.Mode;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
internal class StatisticsHandler
|
internal class StatisticsHandler
|
||||||
{
|
{
|
||||||
private Mode.Config config_;
|
private Config _config;
|
||||||
private GrpcChannel _channel;
|
|
||||||
private StatsService.StatsServiceClient _client;
|
|
||||||
private bool _exitFlag;
|
|
||||||
private ServerStatItem? _serverStatItem;
|
private ServerStatItem? _serverStatItem;
|
||||||
private List<ServerStatItem> _lstServerStat;
|
private List<ServerStatItem> _lstServerStat;
|
||||||
public List<ServerStatItem> ServerStat => _lstServerStat;
|
|
||||||
|
|
||||||
private Action<ServerSpeedItem> _updateFunc;
|
private Action<ServerSpeedItem> _updateFunc;
|
||||||
|
private StatisticsV2ray? _statisticsV2Ray;
|
||||||
|
private StatisticsSingbox? _statisticsSingbox;
|
||||||
|
|
||||||
public bool Enable
|
public List<ServerStatItem> ServerStat => _lstServerStat;
|
||||||
{
|
public bool Enable { get; set; }
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StatisticsHandler(Mode.Config config, Action<ServerSpeedItem> update)
|
public StatisticsHandler(Config config, Action<ServerSpeedItem> update)
|
||||||
{
|
{
|
||||||
config_ = config;
|
_config = config;
|
||||||
Enable = config.guiItem.enableStatistics;
|
Enable = config.guiItem.enableStatistics;
|
||||||
|
if (!Enable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_updateFunc = update;
|
_updateFunc = update;
|
||||||
_exitFlag = false;
|
|
||||||
|
|
||||||
Init();
|
Init();
|
||||||
GrpcInit();
|
|
||||||
|
|
||||||
Task.Run(Run);
|
_statisticsV2Ray = new StatisticsV2ray(config, UpdateServerStat);
|
||||||
}
|
_statisticsSingbox = new StatisticsSingbox(config, UpdateServerStat);
|
||||||
|
|
||||||
private void GrpcInit()
|
|
||||||
{
|
|
||||||
if (_channel == null)
|
|
||||||
{
|
|
||||||
Global.statePort = GetFreePort();
|
|
||||||
|
|
||||||
_channel = GrpcChannel.ForAddress($"{Global.httpProtocol}{Global.Loopback}:{Global.statePort}");
|
|
||||||
_client = new StatsService.StatsServiceClient(_channel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_exitFlag = true;
|
_statisticsV2Ray?.Close();
|
||||||
//channel_.ShutdownAsync();
|
_statisticsSingbox?.Close();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void Run()
|
|
||||||
{
|
|
||||||
while (!_exitFlag)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Enable && _channel.State == ConnectivityState.Ready)
|
|
||||||
{
|
|
||||||
QueryStatsResponse? res = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
res = await _client.QueryStatsAsync(new QueryStatsRequest() { Pattern = "", Reset = true });
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
//Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res != null)
|
|
||||||
{
|
|
||||||
GetServerStatItem(config_.indexId);
|
|
||||||
ParseOutput(res.Stat, out ServerSpeedItem server);
|
|
||||||
|
|
||||||
if (server.proxyUp != 0 || server.proxyDown != 0)
|
|
||||||
{
|
|
||||||
_serverStatItem.todayUp += server.proxyUp;
|
|
||||||
_serverStatItem.todayDown += server.proxyDown;
|
|
||||||
_serverStatItem.totalUp += server.proxyUp;
|
|
||||||
_serverStatItem.totalDown += server.proxyDown;
|
|
||||||
}
|
|
||||||
if (Global.ShowInTaskbar)
|
|
||||||
{
|
|
||||||
server.indexId = config_.indexId;
|
|
||||||
server.todayUp = _serverStatItem.todayUp;
|
|
||||||
server.todayDown = _serverStatItem.todayDown;
|
|
||||||
server.totalUp = _serverStatItem.totalUp;
|
|
||||||
server.totalDown = _serverStatItem.totalDown;
|
|
||||||
_updateFunc(server);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var sleep = config_.guiItem.statisticsFreshRate < 1 ? 1 : config_.guiItem.statisticsFreshRate;
|
|
||||||
Thread.Sleep(1000 * sleep);
|
|
||||||
await _channel.ConnectAsync();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearAllServerStatistics()
|
public void ClearAllServerStatistics()
|
||||||
{
|
{
|
||||||
SqliteHelper.Instance.Execute($"delete from ServerStatItem ");
|
SQLiteHelper.Instance.Execute($"delete from ServerStatItem ");
|
||||||
_serverStatItem = null;
|
_serverStatItem = null;
|
||||||
_lstServerStat = new();
|
_lstServerStat = new();
|
||||||
}
|
}
|
||||||
@@ -124,22 +55,46 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SqliteHelper.Instance.UpdateAll(_lstServerStat);
|
SQLiteHelper.Instance.UpdateAll(_lstServerStat);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Init()
|
private void Init()
|
||||||
{
|
{
|
||||||
SqliteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");
|
SQLiteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");
|
||||||
|
|
||||||
long ticks = DateTime.Now.Date.Ticks;
|
long ticks = DateTime.Now.Date.Ticks;
|
||||||
SqliteHelper.Instance.Execute($"update ServerStatItem set todayUp = 0,todayDown=0,dateNow={ticks} where dateNow<>{ticks}");
|
SQLiteHelper.Instance.Execute($"update ServerStatItem set todayUp = 0,todayDown=0,dateNow={ticks} where dateNow<>{ticks}");
|
||||||
|
|
||||||
_lstServerStat = SqliteHelper.Instance.Table<ServerStatItem>().ToList();
|
_lstServerStat = SQLiteHelper.Instance.Table<ServerStatItem>().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateServerStat(ServerSpeedItem server)
|
||||||
|
{
|
||||||
|
GetServerStatItem(_config.indexId);
|
||||||
|
|
||||||
|
if (_serverStatItem is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (server.proxyUp != 0 || server.proxyDown != 0)
|
||||||
|
{
|
||||||
|
_serverStatItem.todayUp += server.proxyUp;
|
||||||
|
_serverStatItem.todayDown += server.proxyDown;
|
||||||
|
_serverStatItem.totalUp += server.proxyUp;
|
||||||
|
_serverStatItem.totalDown += server.proxyDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
server.indexId = _config.indexId;
|
||||||
|
server.todayUp = _serverStatItem.todayUp;
|
||||||
|
server.todayDown = _serverStatItem.todayDown;
|
||||||
|
server.totalUp = _serverStatItem.totalUp;
|
||||||
|
server.totalDown = _serverStatItem.totalDown;
|
||||||
|
_updateFunc(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetServerStatItem(string indexId)
|
private void GetServerStatItem(string indexId)
|
||||||
@@ -164,7 +119,7 @@ namespace v2rayN.Handler
|
|||||||
todayDown = 0,
|
todayDown = 0,
|
||||||
dateNow = ticks
|
dateNow = ticks
|
||||||
};
|
};
|
||||||
SqliteHelper.Instance.Replace(_serverStatItem);
|
SQLiteHelper.Instance.Replace(_serverStatItem);
|
||||||
_lstServerStat.Add(_serverStatItem);
|
_lstServerStat.Add(_serverStatItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,72 +131,5 @@ namespace v2rayN.Handler
|
|||||||
_serverStatItem.dateNow = ticks;
|
_serverStatItem.dateNow = ticks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParseOutput(Google.Protobuf.Collections.RepeatedField<Stat> source, out ServerSpeedItem server)
|
|
||||||
{
|
|
||||||
server = new();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
foreach (Stat stat in source)
|
|
||||||
{
|
|
||||||
string name = stat.Name;
|
|
||||||
long value = stat.Value / 1024; //KByte
|
|
||||||
string[] nStr = name.Split(">>>".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
string type = "";
|
|
||||||
|
|
||||||
name = name.Trim();
|
|
||||||
|
|
||||||
name = nStr[1];
|
|
||||||
type = nStr[3];
|
|
||||||
|
|
||||||
if (name == Global.agentTag)
|
|
||||||
{
|
|
||||||
if (type == "uplink")
|
|
||||||
{
|
|
||||||
server.proxyUp = value;
|
|
||||||
}
|
|
||||||
else if (type == "downlink")
|
|
||||||
{
|
|
||||||
server.proxyDown = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (name == Global.directTag)
|
|
||||||
{
|
|
||||||
if (type == "uplink")
|
|
||||||
{
|
|
||||||
server.directUp = value;
|
|
||||||
}
|
|
||||||
else if (type == "downlink")
|
|
||||||
{
|
|
||||||
server.directDown = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
//Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetFreePort()
|
|
||||||
{
|
|
||||||
int defaultPort = 28123;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// TCP stack please do me a favor
|
|
||||||
TcpListener l = new(IPAddress.Loopback, 0);
|
|
||||||
l.Start();
|
|
||||||
int port = ((IPEndPoint)l.LocalEndpoint).Port;
|
|
||||||
l.Stop();
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// in case access denied
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
return defaultPort;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Text;
|
||||||
|
using v2rayN.Models;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler
|
||||||
|
{
|
||||||
|
internal class StatisticsSingbox
|
||||||
|
{
|
||||||
|
private Config _config;
|
||||||
|
private bool _exitFlag;
|
||||||
|
private ClientWebSocket? webSocket;
|
||||||
|
private string url = string.Empty;
|
||||||
|
private Action<ServerSpeedItem> _updateFunc;
|
||||||
|
|
||||||
|
public StatisticsSingbox(Config config, Action<ServerSpeedItem> update)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_updateFunc = update;
|
||||||
|
_exitFlag = false;
|
||||||
|
|
||||||
|
Task.Run(() => Run());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Init()
|
||||||
|
{
|
||||||
|
await Task.Delay(5000);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
url = $"ws://{Global.Loopback}:{LazyConfig.Instance.StatePort}/traffic";
|
||||||
|
|
||||||
|
if (webSocket == null)
|
||||||
|
{
|
||||||
|
webSocket = new ClientWebSocket();
|
||||||
|
await webSocket.ConnectAsync(new Uri(url), CancellationToken.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_exitFlag = true;
|
||||||
|
if (webSocket != null)
|
||||||
|
{
|
||||||
|
webSocket.Abort();
|
||||||
|
webSocket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Run()
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
|
||||||
|
while (!_exitFlag)
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!(_config.runningCoreType is ECoreType.sing_box or ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (webSocket != null)
|
||||||
|
{
|
||||||
|
if (webSocket.State == WebSocketState.Aborted
|
||||||
|
|| webSocket.State == WebSocketState.Closed)
|
||||||
|
{
|
||||||
|
webSocket.Abort();
|
||||||
|
webSocket = null;
|
||||||
|
Init();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (webSocket.State != WebSocketState.Open)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var buffer = new byte[1024];
|
||||||
|
var res = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
|
while (!res.CloseStatus.HasValue)
|
||||||
|
{
|
||||||
|
var result = Encoding.UTF8.GetString(buffer, 0, res.Count);
|
||||||
|
if (!Utils.IsNullOrEmpty(result))
|
||||||
|
{
|
||||||
|
ParseOutput(result, out ulong up, out ulong down);
|
||||||
|
|
||||||
|
_updateFunc(new ServerSpeedItem()
|
||||||
|
{
|
||||||
|
proxyUp = (long)(up / 1000),
|
||||||
|
proxyDown = (long)(down / 1000)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
res = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseOutput(string source, out ulong up, out ulong down)
|
||||||
|
{
|
||||||
|
up = 0; down = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var trafficItem = JsonUtils.Deserialize<TrafficItem>(source);
|
||||||
|
if (trafficItem != null)
|
||||||
|
{
|
||||||
|
up = trafficItem.up;
|
||||||
|
down = trafficItem.down;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
using Grpc.Core;
|
||||||
|
using Grpc.Net.Client;
|
||||||
|
using ProtosLib.Statistics;
|
||||||
|
using v2rayN.Models;
|
||||||
|
|
||||||
|
namespace v2rayN.Handler
|
||||||
|
{
|
||||||
|
internal class StatisticsV2ray
|
||||||
|
{
|
||||||
|
private Models.Config _config;
|
||||||
|
private GrpcChannel? _channel;
|
||||||
|
private StatsService.StatsServiceClient? _client;
|
||||||
|
private bool _exitFlag;
|
||||||
|
private Action<ServerSpeedItem> _updateFunc;
|
||||||
|
|
||||||
|
public StatisticsV2ray(Models.Config config, Action<ServerSpeedItem> update)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_updateFunc = update;
|
||||||
|
_exitFlag = false;
|
||||||
|
|
||||||
|
GrpcInit();
|
||||||
|
|
||||||
|
Task.Run(Run);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GrpcInit()
|
||||||
|
{
|
||||||
|
if (_channel is null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_channel = GrpcChannel.ForAddress($"{Global.HttpProtocol}{Global.Loopback}:{LazyConfig.Instance.StatePort}");
|
||||||
|
_client = new StatsService.StatsServiceClient(_channel);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
_exitFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Run()
|
||||||
|
{
|
||||||
|
while (!_exitFlag)
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!(_config.runningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5 or ECoreType.SagerNet))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (_channel?.State == ConnectivityState.Ready)
|
||||||
|
{
|
||||||
|
QueryStatsResponse? res = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_client != null)
|
||||||
|
res = await _client.QueryStatsAsync(new QueryStatsRequest() { Pattern = "", Reset = true });
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res != null)
|
||||||
|
{
|
||||||
|
ParseOutput(res.Stat, out ServerSpeedItem server);
|
||||||
|
_updateFunc(server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_channel != null)
|
||||||
|
await _channel.ConnectAsync();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseOutput(Google.Protobuf.Collections.RepeatedField<Stat> source, out ServerSpeedItem server)
|
||||||
|
{
|
||||||
|
server = new();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (Stat stat in source)
|
||||||
|
{
|
||||||
|
string name = stat.Name;
|
||||||
|
long value = stat.Value / 1024; //KByte
|
||||||
|
string[] nStr = name.Split(">>>".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
string type = "";
|
||||||
|
|
||||||
|
name = name.Trim();
|
||||||
|
|
||||||
|
name = nStr[1];
|
||||||
|
type = nStr[3];
|
||||||
|
|
||||||
|
if (name == Global.ProxyTag)
|
||||||
|
{
|
||||||
|
if (type == "uplink")
|
||||||
|
{
|
||||||
|
server.proxyUp = value;
|
||||||
|
}
|
||||||
|
else if (type == "downlink")
|
||||||
|
{
|
||||||
|
server.proxyDown = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (name == Global.DirectTag)
|
||||||
|
{
|
||||||
|
if (type == "uplink")
|
||||||
|
{
|
||||||
|
server.directUp = value;
|
||||||
|
}
|
||||||
|
else if (type == "downlink")
|
||||||
|
{
|
||||||
|
server.directDown = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,5 @@
|
|||||||
using PacLib;
|
using PacLib;
|
||||||
using System.Diagnostics;
|
using v2rayN.Models;
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using v2rayN.Mode;
|
|
||||||
using v2rayN.Properties;
|
|
||||||
using v2rayN.Tool;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
{
|
{
|
||||||
@@ -20,7 +15,6 @@ namespace v2rayN.Handler
|
|||||||
// <proxy-server><CR-LF>
|
// <proxy-server><CR-LF>
|
||||||
// <bypass-list><CR-LF>
|
// <bypass-list><CR-LF>
|
||||||
// <pac-url>
|
// <pac-url>
|
||||||
private static SysproxyConfig? _userSettings = null;
|
|
||||||
|
|
||||||
private enum RET_ERRORS : int
|
private enum RET_ERRORS : int
|
||||||
{
|
{
|
||||||
@@ -34,15 +28,6 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
static SysProxyHandle()
|
static SysProxyHandle()
|
||||||
{
|
{
|
||||||
try
|
|
||||||
{
|
|
||||||
FileManager.UncompressFile(Utils.GetTempPath("sysproxy.exe"),
|
|
||||||
Environment.Is64BitOperatingSystem ? Resources.sysproxy64_exe : Resources.sysproxy_exe);
|
|
||||||
}
|
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool UpdateSysProxy(Config config, bool forceDisable)
|
public static bool UpdateSysProxy(Config config, bool forceDisable)
|
||||||
@@ -56,16 +41,16 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int port = LazyConfig.Instance.GetLocalPort(Global.InboundHttp);
|
int port = LazyConfig.Instance.GetLocalPort(EInboundProtocol.http);
|
||||||
int portSocks = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
|
int portSocks = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||||
int portPac = LazyConfig.Instance.GetLocalPort(ESysProxyType.Pac.ToString());
|
int portPac = LazyConfig.Instance.GetLocalPort(EInboundProtocol.pac);
|
||||||
if (port <= 0)
|
if (port <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (type == ESysProxyType.ForcedChange)
|
if (type == ESysProxyType.ForcedChange)
|
||||||
{
|
{
|
||||||
var strExceptions = $"{config.constItem.defIEProxyExceptions};{config.systemProxyExceptions}";
|
var strExceptions = $"<local>;{config.constItem.defIEProxyExceptions};{config.systemProxyExceptions}";
|
||||||
|
|
||||||
var strProxy = string.Empty;
|
var strProxy = string.Empty;
|
||||||
if (Utils.IsNullOrEmpty(config.systemProxyAdvancedProtocol))
|
if (Utils.IsNullOrEmpty(config.systemProxyAdvancedProtocol))
|
||||||
@@ -79,11 +64,11 @@ namespace v2rayN.Handler
|
|||||||
.Replace("{http_port}", port.ToString())
|
.Replace("{http_port}", port.ToString())
|
||||||
.Replace("{socks_port}", portSocks.ToString());
|
.Replace("{socks_port}", portSocks.ToString());
|
||||||
}
|
}
|
||||||
SetIEProxy(true, strProxy, strExceptions);
|
ProxySetting.SetProxy(strProxy, strExceptions, 2); // set a named proxy
|
||||||
}
|
}
|
||||||
else if (type == ESysProxyType.ForcedClear)
|
else if (type == ESysProxyType.ForcedClear)
|
||||||
{
|
{
|
||||||
ResetIEProxy();
|
ProxySetting.UnsetProxy(); // set to no proxy
|
||||||
}
|
}
|
||||||
else if (type == ESysProxyType.Unchanged)
|
else if (type == ESysProxyType.Unchanged)
|
||||||
{
|
{
|
||||||
@@ -91,8 +76,8 @@ namespace v2rayN.Handler
|
|||||||
else if (type == ESysProxyType.Pac)
|
else if (type == ESysProxyType.Pac)
|
||||||
{
|
{
|
||||||
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
|
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
|
||||||
var strProxy = $"{Global.httpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
|
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
|
||||||
SetIEProxy(false, strProxy, "");
|
ProxySetting.SetProxy(strProxy, "", 4); // use pac script url for auto-config proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != ESysProxyType.Pac)
|
if (type != ESysProxyType.Pac)
|
||||||
@@ -102,7 +87,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -118,115 +103,5 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetIEProxy(bool global, string strProxy, string strExceptions)
|
|
||||||
{
|
|
||||||
string arguments = global
|
|
||||||
? $"global {strProxy} {strExceptions}"
|
|
||||||
: $"pac {strProxy}";
|
|
||||||
|
|
||||||
ExecSysproxy(arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set system proxy to 1 (null) (null) (null)
|
|
||||||
public static bool ResetIEProxy()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// clear user-wininet.json
|
|
||||||
//_userSettings = new SysproxyConfig();
|
|
||||||
//Save();
|
|
||||||
// clear system setting
|
|
||||||
ExecSysproxy("set 1 - - -");
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ExecSysproxy(string arguments)
|
|
||||||
{
|
|
||||||
// using event to avoid hanging when redirect standard output/error
|
|
||||||
// ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why
|
|
||||||
// and http://blog.csdn.net/zhangweixing0/article/details/7356841
|
|
||||||
using AutoResetEvent outputWaitHandle = new(false);
|
|
||||||
using AutoResetEvent errorWaitHandle = new(false);
|
|
||||||
using Process process = new();
|
|
||||||
|
|
||||||
// Configure the process using the StartInfo properties.
|
|
||||||
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
|
|
||||||
process.StartInfo.Arguments = arguments;
|
|
||||||
process.StartInfo.WorkingDirectory = Utils.GetTempPath();
|
|
||||||
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
|
||||||
process.StartInfo.UseShellExecute = false;
|
|
||||||
process.StartInfo.RedirectStandardError = true;
|
|
||||||
process.StartInfo.RedirectStandardOutput = true;
|
|
||||||
|
|
||||||
// Need to provide encoding info, or output/error strings we got will be wrong.
|
|
||||||
process.StartInfo.StandardOutputEncoding = Encoding.Unicode;
|
|
||||||
process.StartInfo.StandardErrorEncoding = Encoding.Unicode;
|
|
||||||
|
|
||||||
process.StartInfo.CreateNoWindow = true;
|
|
||||||
|
|
||||||
StringBuilder output = new(1024);
|
|
||||||
StringBuilder error = new(1024);
|
|
||||||
|
|
||||||
process.OutputDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (e.Data == null)
|
|
||||||
{
|
|
||||||
outputWaitHandle.Set();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
output.AppendLine(e.Data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
process.ErrorDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (e.Data == null)
|
|
||||||
{
|
|
||||||
errorWaitHandle.Set();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
error.AppendLine(e.Data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
try
|
|
||||||
{
|
|
||||||
process.Start();
|
|
||||||
|
|
||||||
process.BeginErrorReadLine();
|
|
||||||
process.BeginOutputReadLine();
|
|
||||||
|
|
||||||
process.WaitForExit();
|
|
||||||
}
|
|
||||||
catch (System.ComponentModel.Win32Exception e)
|
|
||||||
{
|
|
||||||
// log the arguments
|
|
||||||
throw new Exception(process.StartInfo.Arguments);
|
|
||||||
}
|
|
||||||
string stderr = error.ToString();
|
|
||||||
string stdout = output.ToString();
|
|
||||||
|
|
||||||
int exitCode = process.ExitCode;
|
|
||||||
if (exitCode != (int)RET_ERRORS.RET_NO_ERROR)
|
|
||||||
{
|
|
||||||
throw new Exception(stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//if (arguments == "query")
|
|
||||||
//{
|
|
||||||
// if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty())
|
|
||||||
// {
|
|
||||||
// throw new Exception("failed to query wininet settings");
|
|
||||||
// }
|
|
||||||
// _queryStr = stdout;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,358 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Reactive.Linq;
|
|
||||||
using v2rayN.Handler;
|
|
||||||
using v2rayN.Mode;
|
|
||||||
using v2rayN.Resx;
|
|
||||||
|
|
||||||
namespace v2rayN.Base
|
|
||||||
{
|
|
||||||
public sealed class TunHandler
|
|
||||||
{
|
|
||||||
private static readonly Lazy<TunHandler> _instance = new(() => new());
|
|
||||||
public static TunHandler Instance => _instance.Value;
|
|
||||||
private string _tunConfigName = "tunConfig.json";
|
|
||||||
private static Config _config;
|
|
||||||
private CoreInfo coreInfo;
|
|
||||||
private Process? _process;
|
|
||||||
private static int _socksPort;
|
|
||||||
private static bool _needRestart = true;
|
|
||||||
private static bool _isRunning = false;
|
|
||||||
|
|
||||||
public TunHandler()
|
|
||||||
{
|
|
||||||
_config = LazyConfig.Instance.GetConfig();
|
|
||||||
|
|
||||||
Observable.Interval(TimeSpan.FromSeconds(10))
|
|
||||||
.Subscribe(x =>
|
|
||||||
{
|
|
||||||
if (_isRunning && _config.tunModeItem.enableTun)
|
|
||||||
{
|
|
||||||
if (_process == null || _process.HasExited)
|
|
||||||
{
|
|
||||||
if (Init() == false)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CoreStart();
|
|
||||||
Utils.SaveLog("Tun mode monitors restart");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Start()
|
|
||||||
{
|
|
||||||
var socksPort = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
|
|
||||||
|
|
||||||
if (socksPort == _socksPort
|
|
||||||
&& _process != null
|
|
||||||
&& !_process.HasExited)
|
|
||||||
{
|
|
||||||
_needRestart = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_socksPort = socksPort;
|
|
||||||
|
|
||||||
if (_needRestart)
|
|
||||||
{
|
|
||||||
CoreStop();
|
|
||||||
if (Init() == false)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CoreStartTest();
|
|
||||||
CoreStart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop()
|
|
||||||
{
|
|
||||||
CoreStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool Init()
|
|
||||||
{
|
|
||||||
coreInfo = LazyConfig.Instance.GetCoreInfo(ECoreType.sing_box);
|
|
||||||
//Template
|
|
||||||
string configStr = Utils.GetEmbedText(Global.TunSingboxFileName);
|
|
||||||
if (!Utils.IsNullOrEmpty(_config.tunModeItem.customTemplate) && File.Exists(_config.tunModeItem.customTemplate))
|
|
||||||
{
|
|
||||||
var customTemplate = File.ReadAllText(_config.tunModeItem.customTemplate);
|
|
||||||
if (!Utils.IsNullOrEmpty(customTemplate))
|
|
||||||
{
|
|
||||||
configStr = customTemplate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Utils.IsNullOrEmpty(configStr))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//settings
|
|
||||||
if (_config.tunModeItem.mtu <= 0)
|
|
||||||
{
|
|
||||||
_config.tunModeItem.mtu = Convert.ToInt32(Global.TunMtus[0]);
|
|
||||||
}
|
|
||||||
if (Utils.IsNullOrEmpty(_config.tunModeItem.stack))
|
|
||||||
{
|
|
||||||
_config.tunModeItem.stack = Global.TunStacks[0];
|
|
||||||
}
|
|
||||||
configStr = configStr.Replace("$mtu$", $"{_config.tunModeItem.mtu}");
|
|
||||||
configStr = configStr.Replace("$strict_route$", $"{_config.tunModeItem.strictRoute.ToString().ToLower()}");
|
|
||||||
configStr = configStr.Replace("$stack$", $"{_config.tunModeItem.stack}");
|
|
||||||
|
|
||||||
//logs
|
|
||||||
configStr = configStr.Replace("$log_disabled$", $"{(!_config.tunModeItem.enabledLog).ToString().ToLower()}");
|
|
||||||
if (_config.tunModeItem.showWindow)
|
|
||||||
{
|
|
||||||
configStr = configStr.Replace("$log_output$", $"");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var dtNow = DateTime.Now;
|
|
||||||
var log_output = $"\"output\": \"{Utils.GetLogPath($"singbox_{dtNow:yyyy-MM-dd}.txt")}\", ";
|
|
||||||
configStr = configStr.Replace("$log_output$", $"{log_output.Replace(@"\", @"\\")}");
|
|
||||||
}
|
|
||||||
|
|
||||||
//port
|
|
||||||
configStr = configStr.Replace("$socksPort$", $"{_socksPort}");
|
|
||||||
|
|
||||||
//dns
|
|
||||||
string dnsObject = String.Empty;
|
|
||||||
if (_config.tunModeItem.bypassMode)
|
|
||||||
{
|
|
||||||
dnsObject = _config.tunModeItem.directDNS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dnsObject = _config.tunModeItem.proxyDNS;
|
|
||||||
}
|
|
||||||
if (dnsObject.IsNullOrEmpty() || Utils.ParseJson(dnsObject)?.ContainsKey("servers") == false)
|
|
||||||
{
|
|
||||||
dnsObject = Utils.GetEmbedText(Global.TunSingboxDNSFileName);
|
|
||||||
}
|
|
||||||
configStr = configStr.Replace("$dns_object$", dnsObject);
|
|
||||||
|
|
||||||
//exe
|
|
||||||
List<string> lstDnsExe = new();
|
|
||||||
List<string> lstDirectExe = new();
|
|
||||||
var coreInfos = LazyConfig.Instance.GetCoreInfos();
|
|
||||||
foreach (var it in coreInfos)
|
|
||||||
{
|
|
||||||
if (it.coreType == ECoreType.v2rayN)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
foreach (var it2 in it.coreExes)
|
|
||||||
{
|
|
||||||
if (!lstDnsExe.Contains(it2) && it.coreType != ECoreType.sing_box)
|
|
||||||
{
|
|
||||||
//lstDnsExe.Add(it2);
|
|
||||||
lstDnsExe.Add($"{it2}.exe");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lstDirectExe.Contains(it2))
|
|
||||||
{
|
|
||||||
//lstDirectExe.Add(it2);
|
|
||||||
lstDirectExe.Add($"{it2}.exe");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
string strDns = string.Join("\",\"", lstDnsExe.ToArray());
|
|
||||||
configStr = configStr.Replace("$dnsProcessName$", $"\"{strDns}\"");
|
|
||||||
|
|
||||||
string strDirect = string.Join("\",\"", lstDirectExe.ToArray());
|
|
||||||
configStr = configStr.Replace("$directProcessName$", $"\"{strDirect}\"");
|
|
||||||
|
|
||||||
if (_config.tunModeItem.bypassMode)
|
|
||||||
{
|
|
||||||
//direct ips
|
|
||||||
if (_config.tunModeItem.directIP != null && _config.tunModeItem.directIP.Count > 0)
|
|
||||||
{
|
|
||||||
var ips = new { outbound = "direct", ip_cidr = _config.tunModeItem.directIP };
|
|
||||||
configStr = configStr.Replace("$ruleDirectIPs$", "," + Utils.ToJson(ips));
|
|
||||||
}
|
|
||||||
//direct process
|
|
||||||
if (_config.tunModeItem.directProcess != null && _config.tunModeItem.directProcess.Count > 0)
|
|
||||||
{
|
|
||||||
var process = new { outbound = "direct", process_name = _config.tunModeItem.directProcess };
|
|
||||||
configStr = configStr.Replace("$ruleDirectProcess$", "," + Utils.ToJson(process));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//proxy ips
|
|
||||||
if (_config.tunModeItem.proxyIP != null && _config.tunModeItem.proxyIP.Count > 0)
|
|
||||||
{
|
|
||||||
var ips = new { outbound = "proxy", ip_cidr = _config.tunModeItem.proxyIP };
|
|
||||||
configStr = configStr.Replace("$ruleProxyIPs$", "," + Utils.ToJson(ips));
|
|
||||||
}
|
|
||||||
//proxy process
|
|
||||||
if (_config.tunModeItem.proxyProcess != null && _config.tunModeItem.proxyProcess.Count > 0)
|
|
||||||
{
|
|
||||||
var process = new { outbound = "proxy", process_name = _config.tunModeItem.proxyProcess };
|
|
||||||
configStr = configStr.Replace("$ruleProxyProcess$", "," + Utils.ToJson(process));
|
|
||||||
}
|
|
||||||
|
|
||||||
var final = new { outbound = "direct", inbound = "tun-in" };
|
|
||||||
configStr = configStr.Replace("$ruleFinally$", "," + Utils.ToJson(final));
|
|
||||||
}
|
|
||||||
configStr = configStr.Replace("$ruleDirectIPs$", "");
|
|
||||||
configStr = configStr.Replace("$ruleDirectProcess$", "");
|
|
||||||
configStr = configStr.Replace("$ruleProxyIPs$", "");
|
|
||||||
configStr = configStr.Replace("$ruleProxyProcess$", "");
|
|
||||||
configStr = configStr.Replace("$ruleFinally$", "");
|
|
||||||
|
|
||||||
File.WriteAllText(Utils.GetConfigPath(_tunConfigName), configStr);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CoreStop()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_isRunning = false;
|
|
||||||
if (_process != null)
|
|
||||||
{
|
|
||||||
KillProcess(_process);
|
|
||||||
_process.Dispose();
|
|
||||||
_process = null;
|
|
||||||
_needRestart = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string CoreFindexe()
|
|
||||||
{
|
|
||||||
string fileName = string.Empty;
|
|
||||||
foreach (string name in coreInfo.coreExes)
|
|
||||||
{
|
|
||||||
string vName = $"{name}.exe";
|
|
||||||
vName = Utils.GetBinPath(vName, coreInfo.coreType);
|
|
||||||
if (File.Exists(vName))
|
|
||||||
{
|
|
||||||
fileName = vName;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
|
||||||
{
|
|
||||||
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
|
|
||||||
Utils.SaveLog(msg);
|
|
||||||
}
|
|
||||||
return fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CoreStart()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string fileName = CoreFindexe();
|
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var showWindow = _config.tunModeItem.showWindow;
|
|
||||||
Process p = new()
|
|
||||||
{
|
|
||||||
StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = fileName,
|
|
||||||
Arguments = $"run -c \"{Utils.GetConfigPath(_tunConfigName)}\"",
|
|
||||||
WorkingDirectory = Utils.GetConfigPath(),
|
|
||||||
UseShellExecute = showWindow,
|
|
||||||
CreateNoWindow = !showWindow,
|
|
||||||
//RedirectStandardError = !showWindow,
|
|
||||||
Verb = "runas",
|
|
||||||
}
|
|
||||||
};
|
|
||||||
p.Start();
|
|
||||||
_process = p;
|
|
||||||
_isRunning = true;
|
|
||||||
if (p.WaitForExit(1000))
|
|
||||||
{
|
|
||||||
//if (showWindow)
|
|
||||||
//{
|
|
||||||
throw new Exception("start tun mode fail");
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// throw new Exception(p.StandardError.ReadToEnd());
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
Global.processJob.AddProcess(p.Handle);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void KillProcess(Process p)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
p.CloseMainWindow();
|
|
||||||
p.WaitForExit(100);
|
|
||||||
if (!p.HasExited)
|
|
||||||
{
|
|
||||||
p.Kill();
|
|
||||||
p.WaitForExit(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int CoreStartTest()
|
|
||||||
{
|
|
||||||
Utils.SaveLog("Tun mode configuration file test start");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string fileName = CoreFindexe();
|
|
||||||
if (fileName == "")
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
Process p = new Process
|
|
||||||
{
|
|
||||||
StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = fileName,
|
|
||||||
Arguments = $"run -c \"{Utils.GetConfigPath(_tunConfigName)}\"",
|
|
||||||
WorkingDirectory = Utils.GetConfigPath(),
|
|
||||||
UseShellExecute = false,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
Verb = "runas",
|
|
||||||
}
|
|
||||||
};
|
|
||||||
p.Start();
|
|
||||||
if (p.WaitForExit(2000))
|
|
||||||
{
|
|
||||||
throw new Exception(p.StandardError.ReadToEnd());
|
|
||||||
}
|
|
||||||
KillProcess(p);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
Utils.SaveLog("Tun mode configuration file test end");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,8 +6,7 @@ using System.Runtime.InteropServices;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using v2rayN.Base;
|
using v2rayN.Models;
|
||||||
using v2rayN.Mode;
|
|
||||||
using v2rayN.Resx;
|
using v2rayN.Resx;
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace v2rayN.Handler
|
||||||
@@ -23,11 +22,13 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
public bool Success;
|
public bool Success;
|
||||||
public string Msg;
|
public string Msg;
|
||||||
|
public string Url;
|
||||||
|
|
||||||
public ResultEventArgs(bool success, string msg)
|
public ResultEventArgs(bool success, string msg, string url = "")
|
||||||
{
|
{
|
||||||
Success = success;
|
Success = success;
|
||||||
Msg = msg;
|
Msg = msg;
|
||||||
|
Url = url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ namespace v2rayN.Handler
|
|||||||
StartInfo = new ProcessStartInfo
|
StartInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = "v2rayUpgrade.exe",
|
FileName = "v2rayUpgrade.exe",
|
||||||
Arguments = $"\"{fileName}\"",
|
Arguments = fileName.AppendQuotes(),
|
||||||
WorkingDirectory = Utils.StartupPath()
|
WorkingDirectory = Utils.StartupPath()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -82,9 +83,13 @@ namespace v2rayN.Handler
|
|||||||
if (args.Success)
|
if (args.Success)
|
||||||
{
|
{
|
||||||
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, "v2rayN"));
|
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, "v2rayN"));
|
||||||
|
_updateFunc(false, args.Msg);
|
||||||
|
|
||||||
url = args.Msg;
|
url = args.Url;
|
||||||
askToDownload(downloadHandle, url, true);
|
AskToDownload(downloadHandle, url, true).ContinueWith(task =>
|
||||||
|
{
|
||||||
|
_updateFunc(false, url);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -134,8 +139,13 @@ namespace v2rayN.Handler
|
|||||||
if (args.Success)
|
if (args.Success)
|
||||||
{
|
{
|
||||||
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, "Core"));
|
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, "Core"));
|
||||||
url = args.Msg;
|
_updateFunc(false, args.Msg);
|
||||||
askToDownload(downloadHandle, url, true);
|
|
||||||
|
url = args.Url;
|
||||||
|
AskToDownload(downloadHandle, url, true).ContinueWith(task =>
|
||||||
|
{
|
||||||
|
_updateFunc(false, url);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -153,7 +163,7 @@ namespace v2rayN.Handler
|
|||||||
_updateFunc = update;
|
_updateFunc = update;
|
||||||
|
|
||||||
_updateFunc(false, ResUI.MsgUpdateSubscriptionStart);
|
_updateFunc(false, ResUI.MsgUpdateSubscriptionStart);
|
||||||
var subItem = LazyConfig.Instance.SubItems();
|
var subItem = LazyConfig.Instance.SubItems().OrderBy(t => t.sort).ToList();
|
||||||
|
|
||||||
if (subItem == null || subItem.Count <= 0)
|
if (subItem == null || subItem.Count <= 0)
|
||||||
{
|
{
|
||||||
@@ -174,6 +184,10 @@ namespace v2rayN.Handler
|
|||||||
//_updateFunc(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
|
//_updateFunc(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!url.StartsWith(Global.HttpsProtocol) && !url.StartsWith(Global.HttpProtocol))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (item.enabled == false)
|
if (item.enabled == false)
|
||||||
{
|
{
|
||||||
_updateFunc(false, $"{hashCode}{ResUI.MsgSkipSubscriptionUpdate}");
|
_updateFunc(false, $"{hashCode}{ResUI.MsgSkipSubscriptionUpdate}");
|
||||||
@@ -193,7 +207,7 @@ namespace v2rayN.Handler
|
|||||||
//convert
|
//convert
|
||||||
if (!Utils.IsNullOrEmpty(item.convertTarget))
|
if (!Utils.IsNullOrEmpty(item.convertTarget))
|
||||||
{
|
{
|
||||||
var subConvertUrl = string.IsNullOrEmpty(config.constItem.subConvertUrl) ? Global.SubConvertUrls.FirstOrDefault() : config.constItem.subConvertUrl;
|
var subConvertUrl = Utils.IsNullOrEmpty(config.constItem.subConvertUrl) ? Global.SubConvertUrls.FirstOrDefault() : config.constItem.subConvertUrl;
|
||||||
url = string.Format(subConvertUrl!, Utils.UrlEncode(url));
|
url = string.Format(subConvertUrl!, Utils.UrlEncode(url));
|
||||||
if (!url.Contains("target="))
|
if (!url.Contains("target="))
|
||||||
{
|
{
|
||||||
@@ -213,7 +227,7 @@ namespace v2rayN.Handler
|
|||||||
//more url
|
//more url
|
||||||
if (Utils.IsNullOrEmpty(item.convertTarget) && !Utils.IsNullOrEmpty(item.moreUrl.TrimEx()))
|
if (Utils.IsNullOrEmpty(item.convertTarget) && !Utils.IsNullOrEmpty(item.moreUrl.TrimEx()))
|
||||||
{
|
{
|
||||||
if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result))
|
if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result!))
|
||||||
{
|
{
|
||||||
result = Utils.Base64Decode(result);
|
result = Utils.Base64Decode(result);
|
||||||
}
|
}
|
||||||
@@ -237,7 +251,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
if (!Utils.IsNullOrEmpty(result2))
|
if (!Utils.IsNullOrEmpty(result2))
|
||||||
{
|
{
|
||||||
if (Utils.IsBase64String(result2))
|
if (Utils.IsBase64String(result2!))
|
||||||
{
|
{
|
||||||
result += Utils.Base64Decode(result2);
|
result += Utils.Base64Decode(result2);
|
||||||
}
|
}
|
||||||
@@ -256,16 +270,16 @@ namespace v2rayN.Handler
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
|
_updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
|
||||||
if (result!.Length < 99)
|
if (result?.Length < 99)
|
||||||
{
|
{
|
||||||
_updateFunc(false, $"{hashCode}{result}");
|
_updateFunc(false, $"{hashCode}{result}");
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = ConfigHandler.AddBatchServers(ref config, result, id, true);
|
int ret = ConfigHandler.AddBatchServers(config, result, id, true);
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("FailedImportSubscription");
|
Logging.SaveLog("FailedImportSubscription");
|
||||||
Utils.SaveLog(result);
|
Logging.SaveLog(result);
|
||||||
}
|
}
|
||||||
_updateFunc(false,
|
_updateFunc(false,
|
||||||
ret > 0
|
ret > 0
|
||||||
@@ -279,11 +293,273 @@ namespace v2rayN.Handler
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateGeoFile(string geoName, Config config, Action<bool, string> update)
|
public void UpdateGeoFileAll(Config config, Action<bool, string> update)
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await UpdateGeoFile("geosite", _config, update);
|
||||||
|
await UpdateGeoFile("geoip", _config, update);
|
||||||
|
|
||||||
|
//await UpdateGeoFile4Singbox("geosite", _config, false, update);
|
||||||
|
//await UpdateGeoFile4Singbox("geoip", _config, true, update);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RunAvailabilityCheck(Action<bool, string> update)
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var time = await (new DownloadHandle()).RunAvailabilityCheck(null);
|
||||||
|
|
||||||
|
update(false, string.Format(ResUI.TestMeOutput, time));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#region private
|
||||||
|
|
||||||
|
private async void CheckUpdateAsync(ECoreType type, bool preRelease)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
|
||||||
|
string url = coreInfo.coreReleaseApiUrl;
|
||||||
|
|
||||||
|
var result = await (new DownloadHandle()).DownloadStringAsync(url, true, "");
|
||||||
|
if (!Utils.IsNullOrEmpty(result))
|
||||||
|
{
|
||||||
|
responseHandler(type, result, preRelease);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.SaveLog("StatusCode error: " + url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
_updateFunc(false, ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取V2RayCore版本
|
||||||
|
/// </summary>
|
||||||
|
private SemanticVersion getCoreVersion(ECoreType type)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
|
||||||
|
string filePath = string.Empty;
|
||||||
|
foreach (string name in coreInfo.coreExes)
|
||||||
|
{
|
||||||
|
string vName = $"{name}.exe";
|
||||||
|
vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString());
|
||||||
|
if (File.Exists(vName))
|
||||||
|
{
|
||||||
|
filePath = vName;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(filePath))
|
||||||
|
{
|
||||||
|
string msg = string.Format(ResUI.NotFoundCore, @"", "", "");
|
||||||
|
//ShowMsg(true, msg);
|
||||||
|
return new SemanticVersion("");
|
||||||
|
}
|
||||||
|
|
||||||
|
using Process p = new();
|
||||||
|
p.StartInfo.FileName = filePath.AppendQuotes();
|
||||||
|
p.StartInfo.Arguments = coreInfo.versionArg;
|
||||||
|
p.StartInfo.WorkingDirectory = Utils.StartupPath();
|
||||||
|
p.StartInfo.UseShellExecute = false;
|
||||||
|
p.StartInfo.RedirectStandardOutput = true;
|
||||||
|
p.StartInfo.CreateNoWindow = true;
|
||||||
|
p.StartInfo.StandardOutputEncoding = Encoding.UTF8;
|
||||||
|
p.Start();
|
||||||
|
p.WaitForExit(5000);
|
||||||
|
string echo = p.StandardOutput.ReadToEnd();
|
||||||
|
string version = string.Empty;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ECoreType.v2fly:
|
||||||
|
case ECoreType.SagerNet:
|
||||||
|
case ECoreType.Xray:
|
||||||
|
case ECoreType.v2fly_v5:
|
||||||
|
version = Regex.Match(echo, $"{coreInfo.match} ([0-9.]+) \\(").Groups[1].Value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ECoreType.clash:
|
||||||
|
case ECoreType.clash_meta:
|
||||||
|
case ECoreType.mihomo:
|
||||||
|
version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ECoreType.sing_box:
|
||||||
|
version = Regex.Match(echo, $"([0-9.]+)").Groups[1].Value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return new SemanticVersion(version);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
_updateFunc(false, ex.Message);
|
||||||
|
return new SemanticVersion("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void responseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var gitHubReleases = JsonUtils.Deserialize<List<GitHubRelease>>(gitHubReleaseApi);
|
||||||
|
var gitHubRelease = preRelease ? gitHubReleases?.First() : gitHubReleases?.First(r => r.Prerelease == false);
|
||||||
|
var version = new SemanticVersion(gitHubRelease?.TagName!);
|
||||||
|
var body = gitHubRelease?.Body;
|
||||||
|
|
||||||
|
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
|
||||||
|
|
||||||
|
SemanticVersion curVersion;
|
||||||
|
string message;
|
||||||
|
string url;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ECoreType.v2fly:
|
||||||
|
case ECoreType.SagerNet:
|
||||||
|
case ECoreType.Xray:
|
||||||
|
case ECoreType.v2fly_v5:
|
||||||
|
{
|
||||||
|
curVersion = getCoreVersion(type);
|
||||||
|
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
||||||
|
string osBit = "64";
|
||||||
|
switch (RuntimeInformation.ProcessArchitecture)
|
||||||
|
{
|
||||||
|
case Architecture.Arm64:
|
||||||
|
osBit = "arm64-v8a";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Architecture.X86:
|
||||||
|
osBit = "32";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
osBit = "64";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
url = string.Format(coreInfo.coreDownloadUrl64, version.ToVersionString("v"), osBit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ECoreType.clash:
|
||||||
|
case ECoreType.clash_meta:
|
||||||
|
case ECoreType.mihomo:
|
||||||
|
{
|
||||||
|
curVersion = getCoreVersion(type);
|
||||||
|
message = string.Format(ResUI.IsLatestCore, type, curVersion);
|
||||||
|
switch (RuntimeInformation.ProcessArchitecture)
|
||||||
|
{
|
||||||
|
case Architecture.Arm64:
|
||||||
|
url = coreInfo.coreDownloadUrlArm64;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Architecture.X86:
|
||||||
|
url = coreInfo.coreDownloadUrl32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
url = coreInfo.coreDownloadUrl64;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
url = string.Format(url, version.ToVersionString("v"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ECoreType.sing_box:
|
||||||
|
{
|
||||||
|
curVersion = getCoreVersion(type);
|
||||||
|
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
||||||
|
switch (RuntimeInformation.ProcessArchitecture)
|
||||||
|
{
|
||||||
|
case Architecture.Arm64:
|
||||||
|
url = coreInfo.coreDownloadUrlArm64;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Architecture.X86:
|
||||||
|
url = coreInfo.coreDownloadUrl32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
url = coreInfo.coreDownloadUrl64;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
url = string.Format(url, version.ToVersionString("v"), version);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ECoreType.v2rayN:
|
||||||
|
{
|
||||||
|
curVersion = new SemanticVersion(FileVersionInfo.GetVersionInfo(Utils.GetExePath()).FileVersion.ToString());
|
||||||
|
message = string.Format(ResUI.IsLatestN, type, curVersion);
|
||||||
|
switch (RuntimeInformation.ProcessArchitecture)
|
||||||
|
{
|
||||||
|
case Architecture.Arm64:
|
||||||
|
url = string.Format(coreInfo.coreDownloadUrlArm64, version);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Architecture.X86:
|
||||||
|
url = string.Format(coreInfo.coreDownloadUrl32, version);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
url = string.Format(coreInfo.coreDownloadUrl64, version);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curVersion >= version && version != new SemanticVersion(0, 0, 0))
|
||||||
|
{
|
||||||
|
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(true, body, url));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
_updateFunc(false, ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AskToDownload(DownloadHandle downloadHandle, string url, bool blAsk)
|
||||||
|
{
|
||||||
|
bool blDownload = false;
|
||||||
|
if (blAsk)
|
||||||
|
{
|
||||||
|
if (UI.ShowYesNo(string.Format(ResUI.DownloadYesNo, url)) == MessageBoxResult.Yes)
|
||||||
|
{
|
||||||
|
blDownload = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blDownload = true;
|
||||||
|
}
|
||||||
|
if (blDownload)
|
||||||
|
{
|
||||||
|
await downloadHandle.DownloadFileAsync(url, true, 600);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateGeoFile(string geoName, Config config, Action<bool, string> update)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_updateFunc = update;
|
_updateFunc = update;
|
||||||
var url = string.Format(Global.geoUrl, geoName);
|
var url = string.Format(Global.GeoUrl, geoName);
|
||||||
|
|
||||||
DownloadHandle downloadHandle = new();
|
DownloadHandle downloadHandle = new();
|
||||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
downloadHandle.UpdateCompleted += (sender2, args) =>
|
||||||
@@ -299,7 +575,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
//Global.coreTypes.ForEach(it =>
|
//Global.coreTypes.ForEach(it =>
|
||||||
//{
|
//{
|
||||||
// string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
|
// string targetPath = Utile.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
|
||||||
// File.Copy(fileName, targetPath, true);
|
// File.Copy(fileName, targetPath, true);
|
||||||
//});
|
//});
|
||||||
string targetPath = Utils.GetBinPath($"{geoName}.dat");
|
string targetPath = Utils.GetBinPath($"{geoName}.dat");
|
||||||
@@ -323,271 +599,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
_updateFunc(false, args.GetException().Message);
|
_updateFunc(false, args.GetException().Message);
|
||||||
};
|
};
|
||||||
askToDownload(downloadHandle, url, false);
|
await AskToDownload(downloadHandle, url, false);
|
||||||
}
|
|
||||||
|
|
||||||
public void RunAvailabilityCheck(Action<bool, string> update)
|
|
||||||
{
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
var time = (new DownloadHandle()).RunAvailabilityCheck(null);
|
|
||||||
|
|
||||||
update(false, string.Format(ResUI.TestMeOutput, time));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#region private
|
|
||||||
|
|
||||||
private async void CheckUpdateAsync(ECoreType type, bool preRelease)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
|
|
||||||
string url = coreInfo.coreReleaseApiUrl;
|
|
||||||
|
|
||||||
var result = await (new DownloadHandle()).DownloadStringAsync(url, true, "");
|
|
||||||
if (!Utils.IsNullOrEmpty(result))
|
|
||||||
{
|
|
||||||
responseHandler(type, result, preRelease);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Utils.SaveLog("StatusCode error: " + url);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
_updateFunc(false, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取V2RayCore版本
|
|
||||||
/// </summary>
|
|
||||||
private string getCoreVersion(ECoreType type)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
|
|
||||||
string filePath = string.Empty;
|
|
||||||
foreach (string name in coreInfo.coreExes)
|
|
||||||
{
|
|
||||||
string vName = $"{name}.exe";
|
|
||||||
vName = Utils.GetBinPath(vName, coreInfo.coreType);
|
|
||||||
if (File.Exists(vName))
|
|
||||||
{
|
|
||||||
filePath = vName;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!File.Exists(filePath))
|
|
||||||
{
|
|
||||||
string msg = string.Format(ResUI.NotFoundCore, @"", "", "");
|
|
||||||
//ShowMsg(true, msg);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
using Process p = new();
|
|
||||||
p.StartInfo.FileName = filePath;
|
|
||||||
p.StartInfo.Arguments = coreInfo.versionArg;
|
|
||||||
p.StartInfo.WorkingDirectory = Utils.StartupPath();
|
|
||||||
p.StartInfo.UseShellExecute = false;
|
|
||||||
p.StartInfo.RedirectStandardOutput = true;
|
|
||||||
p.StartInfo.CreateNoWindow = true;
|
|
||||||
p.StartInfo.StandardOutputEncoding = Encoding.UTF8;
|
|
||||||
p.Start();
|
|
||||||
p.WaitForExit(5000);
|
|
||||||
string echo = p.StandardOutput.ReadToEnd();
|
|
||||||
string version = string.Empty;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case ECoreType.v2fly:
|
|
||||||
case ECoreType.SagerNet:
|
|
||||||
case ECoreType.Xray:
|
|
||||||
case ECoreType.v2fly_v5:
|
|
||||||
version = Regex.Match(echo, $"{coreInfo.match} ([0-9.]+) \\(").Groups[1].Value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ECoreType.clash:
|
|
||||||
case ECoreType.clash_meta:
|
|
||||||
version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ECoreType.sing_box:
|
|
||||||
version = Regex.Match(echo, $"([0-9.]+)").Groups[1].Value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
_updateFunc(false, ex.Message);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void responseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var gitHubReleases = Utils.FromJson<List<GitHubRelease>>(gitHubReleaseApi);
|
|
||||||
string version;
|
|
||||||
if (preRelease)
|
|
||||||
{
|
|
||||||
version = gitHubReleases!.First().TagName;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
version = gitHubReleases!.First(r => r.Prerelease == false).TagName;
|
|
||||||
}
|
|
||||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
|
|
||||||
|
|
||||||
string curVersion;
|
|
||||||
string message;
|
|
||||||
string url;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case ECoreType.v2fly:
|
|
||||||
case ECoreType.SagerNet:
|
|
||||||
case ECoreType.Xray:
|
|
||||||
case ECoreType.v2fly_v5:
|
|
||||||
{
|
|
||||||
curVersion = "v" + getCoreVersion(type);
|
|
||||||
message = string.Format(ResUI.IsLatestCore, curVersion);
|
|
||||||
string osBit = "64";
|
|
||||||
switch (RuntimeInformation.ProcessArchitecture)
|
|
||||||
{
|
|
||||||
case Architecture.Arm64:
|
|
||||||
osBit = "arm64-v8a";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Architecture.X86:
|
|
||||||
osBit = "32";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
osBit = "64";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
url = string.Format(coreInfo.coreDownloadUrl64, version, osBit);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ECoreType.clash:
|
|
||||||
case ECoreType.clash_meta:
|
|
||||||
{
|
|
||||||
curVersion = getCoreVersion(type);
|
|
||||||
message = string.Format(ResUI.IsLatestCore, curVersion);
|
|
||||||
switch (RuntimeInformation.ProcessArchitecture)
|
|
||||||
{
|
|
||||||
case Architecture.Arm64:
|
|
||||||
url = coreInfo.coreDownloadUrlArm64;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Architecture.X86:
|
|
||||||
url = coreInfo.coreDownloadUrl32;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
url = coreInfo.coreDownloadUrl64;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
url = string.Format(url, version);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ECoreType.sing_box:
|
|
||||||
{
|
|
||||||
curVersion = "v" + getCoreVersion(type);
|
|
||||||
message = string.Format(ResUI.IsLatestCore, curVersion);
|
|
||||||
switch (RuntimeInformation.ProcessArchitecture)
|
|
||||||
{
|
|
||||||
case Architecture.Arm64:
|
|
||||||
url = coreInfo.coreDownloadUrlArm64;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Architecture.X86:
|
|
||||||
url = coreInfo.coreDownloadUrl32;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
url = coreInfo.coreDownloadUrl64;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
url = string.Format(url, version, version.Replace("v", ""));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ECoreType.v2rayN:
|
|
||||||
{
|
|
||||||
curVersion = FileVersionInfo.GetVersionInfo(Utils.GetExePath()).FileVersion.ToString();
|
|
||||||
message = string.Format(ResUI.IsLatestN, curVersion);
|
|
||||||
switch (RuntimeInformation.ProcessArchitecture)
|
|
||||||
{
|
|
||||||
case Architecture.Arm64:
|
|
||||||
url = string.Format(coreInfo.coreDownloadUrlArm64, version);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Architecture.X86:
|
|
||||||
url = string.Format(coreInfo.coreDownloadUrl32, version);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
url = string.Format(coreInfo.coreDownloadUrl64, version);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentException("Type");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == ECoreType.v2rayN)
|
|
||||||
{
|
|
||||||
decimal.TryParse(curVersion, out decimal decCur);
|
|
||||||
decimal.TryParse(version, out decimal dec);
|
|
||||||
if (decCur >= dec)
|
|
||||||
{
|
|
||||||
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curVersion == version)
|
|
||||||
{
|
|
||||||
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(true, url));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Utils.SaveLog(ex.Message, ex);
|
|
||||||
_updateFunc(false, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void askToDownload(DownloadHandle downloadHandle, string url, bool blAsk)
|
|
||||||
{
|
|
||||||
bool blDownload = false;
|
|
||||||
if (blAsk)
|
|
||||||
{
|
|
||||||
if (UI.ShowYesNo(string.Format(ResUI.DownloadYesNo, url)) == MessageBoxResult.Yes)
|
|
||||||
{
|
|
||||||
blDownload = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
blDownload = true;
|
|
||||||
}
|
|
||||||
if (blDownload)
|
|
||||||
{
|
|
||||||
downloadHandle.DownloadFileAsync(url, true, 600);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion private
|
#endregion private
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
|
||||||
{
|
|
||||||
public class GitHubReleaseAsset
|
|
||||||
{
|
|
||||||
[JsonProperty("url")] public string Url { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("id")] public int Id { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("node_id")] public string NodeId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("name")] public string Name { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("label")] public object Label { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("content_type")] public string ContentType { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("state")] public string State { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("size")] public int Size { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("download_count")] public int DownloadCount { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("created_at")] public DateTime CreatedAt { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("updated_at")] public DateTime UpdatedAt { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("browser_download_url")] public string BrowserDownloadUrl { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GitHubRelease
|
|
||||||
{
|
|
||||||
[JsonProperty("url")] public string Url { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("assets_url")] public string AssetsUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("upload_url")] public string UploadUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("html_url")] public string HtmlUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("id")] public int Id { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("node_id")] public string NodeId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("tag_name")] public string TagName { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("target_commitish")] public string TargetCommitish { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("name")] public string Name { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("draft")] public bool Draft { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("prerelease")] public bool Prerelease { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("created_at")] public DateTime CreatedAt { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("published_at")] public DateTime PublishedAt { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("assets")] public List<GitHubReleaseAsset> Assets { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("tarball_url")] public string TarballUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("zipball_url")] public string ZipballUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("body")] public string Body { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
namespace v2rayN.Mode
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// https://github.com/2dust/v2rayN/wiki/
|
|
||||||
/// </summary>
|
|
||||||
[Serializable]
|
|
||||||
internal class VmessQRCode
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string v { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string ps { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string add { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string port { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string id { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string aid { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string scy { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string net { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string type { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string host { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public string path { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TLS
|
|
||||||
/// </summary>
|
|
||||||
public string tls { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TLS SNI
|
|
||||||
/// </summary>
|
|
||||||
public string sni { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TLS alpn
|
|
||||||
/// </summary>
|
|
||||||
public string alpn { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TLS fingerprint
|
|
||||||
/// </summary>
|
|
||||||
public string fp { get; set; } = string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public class ComboItem
|
public class ComboItem
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 本软件配置文件实体类
|
/// 本软件配置文件实体类
|
||||||
@@ -10,18 +10,12 @@
|
|||||||
|
|
||||||
public string indexId { get; set; }
|
public string indexId { get; set; }
|
||||||
public string subIndexId { get; set; }
|
public string subIndexId { get; set; }
|
||||||
|
|
||||||
public string remoteDNS { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Outbound Freedom domainStrategy
|
|
||||||
/// </summary>
|
|
||||||
public string domainStrategy4Freedom { get; set; }
|
|
||||||
|
|
||||||
public ESysProxyType sysProxyType { get; set; }
|
public ESysProxyType sysProxyType { get; set; }
|
||||||
public string systemProxyExceptions { get; set; }
|
public string systemProxyExceptions { get; set; }
|
||||||
public string systemProxyAdvancedProtocol { get; set; }
|
public string systemProxyAdvancedProtocol { get; set; }
|
||||||
|
|
||||||
|
public ECoreType runningCoreType { get; set; }
|
||||||
|
|
||||||
#endregion property
|
#endregion property
|
||||||
|
|
||||||
#region other entities
|
#region other entities
|
||||||
@@ -35,6 +29,8 @@
|
|||||||
public UIItem uiItem { get; set; }
|
public UIItem uiItem { get; set; }
|
||||||
public ConstItem constItem { get; set; }
|
public ConstItem constItem { get; set; }
|
||||||
public SpeedTestItem speedTestItem { get; set; }
|
public SpeedTestItem speedTestItem { get; set; }
|
||||||
|
public Mux4SboxItem mux4SboxItem { get; set; }
|
||||||
|
public HysteriaItem hysteriaItem { get; set; }
|
||||||
public List<InItem> inbound { get; set; }
|
public List<InItem> inbound { get; set; }
|
||||||
public List<KeyEventItem> globalHotkeys { get; set; }
|
public List<KeyEventItem> globalHotkeys { get; set; }
|
||||||
public List<CoreTypeItem> coreTypeItem { get; set; }
|
public List<CoreTypeItem> coreTypeItem { get; set; }
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CoreBasicItem
|
public class CoreBasicItem
|
||||||
@@ -31,6 +31,10 @@ namespace v2rayN.Mode
|
|||||||
/// 默认用户代理
|
/// 默认用户代理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string defUserAgent { get; set; }
|
public string defUserAgent { get; set; }
|
||||||
|
|
||||||
|
public bool enableFragment { get; set; }
|
||||||
|
|
||||||
|
public bool enableCacheFile4Sbox { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -43,8 +47,8 @@ namespace v2rayN.Mode
|
|||||||
public bool udpEnabled { get; set; }
|
public bool udpEnabled { get; set; }
|
||||||
|
|
||||||
public bool sniffingEnabled { get; set; } = true;
|
public bool sniffingEnabled { get; set; } = true;
|
||||||
|
public List<string>? destOverride { get; set; } = ["http", "tls"];
|
||||||
public bool routeOnly { get; set; }
|
public bool routeOnly { get; set; }
|
||||||
|
|
||||||
public bool allowLANConn { get; set; }
|
public bool allowLANConn { get; set; }
|
||||||
|
|
||||||
public bool newPort4LAN { get; set; }
|
public bool newPort4LAN { get; set; }
|
||||||
@@ -88,8 +92,6 @@ namespace v2rayN.Mode
|
|||||||
|
|
||||||
public bool enableStatistics { get; set; }
|
public bool enableStatistics { get; set; }
|
||||||
|
|
||||||
public int statisticsFreshRate { get; set; }
|
|
||||||
|
|
||||||
public bool keepOlderDedupl { get; set; }
|
public bool keepOlderDedupl { get; set; }
|
||||||
|
|
||||||
public bool ignoreGeoUpdateCore { get; set; } = true;
|
public bool ignoreGeoUpdateCore { get; set; } = true;
|
||||||
@@ -111,20 +113,21 @@ namespace v2rayN.Mode
|
|||||||
public class UIItem
|
public class UIItem
|
||||||
{
|
{
|
||||||
public bool enableAutoAdjustMainLvColWidth { get; set; }
|
public bool enableAutoAdjustMainLvColWidth { get; set; }
|
||||||
|
public bool enableUpdateSubOnlyRemarksExist { get; set; }
|
||||||
public double mainWidth { get; set; }
|
public double mainWidth { get; set; }
|
||||||
public double mainHeight { get; set; }
|
public double mainHeight { get; set; }
|
||||||
public double mainGirdHeight1 { get; set; }
|
public double mainGirdHeight1 { get; set; }
|
||||||
public double mainGirdHeight2 { get; set; }
|
public double mainGirdHeight2 { get; set; }
|
||||||
public bool colorModeDark { get; set; }
|
public bool colorModeDark { get; set; }
|
||||||
|
public bool followSystemTheme { get; set; }
|
||||||
public string? colorPrimaryName { get; set; }
|
public string? colorPrimaryName { get; set; }
|
||||||
public string currentLanguage { get; set; }
|
public string currentLanguage { get; set; }
|
||||||
public string currentFontFamily { get; set; }
|
public string currentFontFamily { get; set; }
|
||||||
public int currentFontSize { get; set; }
|
public int currentFontSize { get; set; }
|
||||||
public bool enableDragDropSort { get; set; }
|
public bool enableDragDropSort { get; set; }
|
||||||
public bool doubleClick2Activate { get; set; }
|
public bool doubleClick2Activate { get; set; }
|
||||||
public bool autoHideStartup { get; set; } = true;
|
public bool autoHideStartup { get; set; }
|
||||||
public string mainMsgFilter { get; set; }
|
public string mainMsgFilter { get; set; }
|
||||||
public bool showTrayTip { get; set; }
|
|
||||||
public List<ColumnItem> mainColumnItem { get; set; }
|
public List<ColumnItem> mainColumnItem { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,19 +164,11 @@ namespace v2rayN.Mode
|
|||||||
public class TunModeItem
|
public class TunModeItem
|
||||||
{
|
{
|
||||||
public bool enableTun { get; set; }
|
public bool enableTun { get; set; }
|
||||||
public bool showWindow { get; set; }
|
public bool strictRoute { get; set; } = true;
|
||||||
public bool enabledLog { get; set; }
|
|
||||||
public bool strictRoute { get; set; }
|
|
||||||
public string stack { get; set; }
|
public string stack { get; set; }
|
||||||
public int mtu { get; set; }
|
public int mtu { get; set; }
|
||||||
public string customTemplate { get; set; }
|
public bool enableExInbound { get; set; }
|
||||||
public bool bypassMode { get; set; } = true;
|
public bool enableIPv6Address { get; set; } = true;
|
||||||
public List<string> directIP { get; set; }
|
|
||||||
public List<string> directProcess { get; set; }
|
|
||||||
public string directDNS { get; set; }
|
|
||||||
public List<string> proxyIP { get; set; }
|
|
||||||
public List<string> proxyProcess { get; set; }
|
|
||||||
public string proxyDNS { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -187,14 +182,11 @@ namespace v2rayN.Mode
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class RoutingBasicItem
|
public class RoutingBasicItem
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 域名解析策略
|
|
||||||
/// </summary>
|
|
||||||
public string domainStrategy { get; set; }
|
public string domainStrategy { get; set; }
|
||||||
|
public string domainStrategy4Singbox { get; set; }
|
||||||
public string domainMatcher { get; set; }
|
public string domainMatcher { get; set; }
|
||||||
public string routingIndexId { get; set; }
|
public string routingIndexId { get; set; }
|
||||||
public bool enableRoutingAdvanced { get; set; }
|
public bool enableRoutingAdvanced { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -204,4 +196,18 @@ namespace v2rayN.Mode
|
|||||||
public int Width { get; set; }
|
public int Width { get; set; }
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Mux4SboxItem
|
||||||
|
{
|
||||||
|
public string protocol { get; set; }
|
||||||
|
public int max_connections { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class HysteriaItem
|
||||||
|
{
|
||||||
|
public int up_mbps { get; set; }
|
||||||
|
public int down_mbps { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ConfigOld
|
public class ConfigOld
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CoreInfo
|
public class CoreInfo
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using SQLite;
|
||||||
|
|
||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class DNSItem
|
||||||
|
{
|
||||||
|
[PrimaryKey]
|
||||||
|
public string id { get; set; }
|
||||||
|
|
||||||
|
public string remarks { get; set; }
|
||||||
|
public bool enabled { get; set; } = true;
|
||||||
|
public ECoreType coreType { get; set; }
|
||||||
|
public bool useSystemHosts { get; set; }
|
||||||
|
public string? normalDNS { get; set; }
|
||||||
|
public string? tunDNS { get; set; }
|
||||||
|
public string? domainStrategy4Freedom { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public enum EConfigType
|
public enum EConfigType
|
||||||
{
|
{
|
||||||
@@ -7,6 +7,10 @@
|
|||||||
Shadowsocks = 3,
|
Shadowsocks = 3,
|
||||||
Socks = 4,
|
Socks = 4,
|
||||||
VLESS = 5,
|
VLESS = 5,
|
||||||
Trojan = 6
|
Trojan = 6,
|
||||||
|
Hysteria2 = 7,
|
||||||
|
Tuic = 8,
|
||||||
|
Wireguard = 9,
|
||||||
|
Http = 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public enum ECoreType
|
public enum ECoreType
|
||||||
{
|
{
|
||||||
@@ -8,10 +8,13 @@
|
|||||||
v2fly_v5 = 4,
|
v2fly_v5 = 4,
|
||||||
clash = 11,
|
clash = 11,
|
||||||
clash_meta = 12,
|
clash_meta = 12,
|
||||||
|
mihomo = 13,
|
||||||
hysteria = 21,
|
hysteria = 21,
|
||||||
naiveproxy = 22,
|
naiveproxy = 22,
|
||||||
tuic = 23,
|
tuic = 23,
|
||||||
sing_box = 24,
|
sing_box = 24,
|
||||||
|
juicity = 25,
|
||||||
|
hysteria2 = 26,
|
||||||
v2rayN = 99
|
v2rayN = 99
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public enum EGlobalHotkey
|
public enum EGlobalHotkey
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public enum EInboundProtocol
|
||||||
|
{
|
||||||
|
socks = 0,
|
||||||
|
http,
|
||||||
|
socks2,
|
||||||
|
http2,
|
||||||
|
pac,
|
||||||
|
api,
|
||||||
|
speedtest = 21
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public enum EMove
|
public enum EMove
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public enum EServerColName
|
public enum EServerColName
|
||||||
{
|
{
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
remarks,
|
remarks,
|
||||||
address,
|
address,
|
||||||
port,
|
port,
|
||||||
security,
|
|
||||||
network,
|
network,
|
||||||
streamSecurity,
|
streamSecurity,
|
||||||
subRemarks,
|
subRemarks,
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public enum ESpeedActionType
|
public enum ESpeedActionType
|
||||||
{
|
{
|
||||||
Ping,
|
|
||||||
Tcping,
|
Tcping,
|
||||||
Realping,
|
Realping,
|
||||||
Speedtest,
|
Speedtest,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public enum ESysProxyType
|
public enum ESysProxyType
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public enum ETransport
|
||||||
|
{
|
||||||
|
tcp,
|
||||||
|
kcp,
|
||||||
|
ws,
|
||||||
|
httpupgrade,
|
||||||
|
h2,
|
||||||
|
http,
|
||||||
|
quic,
|
||||||
|
grpc
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public enum EViewAction
|
public enum EViewAction
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public class GitHubReleaseAsset
|
||||||
|
{
|
||||||
|
[JsonPropertyName("url")] public string Url { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("id")] public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("node_id")] public string NodeId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("name")] public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("label")] public object Label { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("content_type")] public string ContentType { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("state")] public string State { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("size")] public int Size { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("download_count")] public int DownloadCount { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("updated_at")] public DateTime UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("browser_download_url")] public string BrowserDownloadUrl { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GitHubRelease
|
||||||
|
{
|
||||||
|
[JsonPropertyName("url")] public string Url { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("assets_url")] public string AssetsUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("upload_url")] public string UploadUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("html_url")] public string HtmlUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("id")] public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("node_id")] public string NodeId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("tag_name")] public string TagName { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("target_commitish")] public string TargetCommitish { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("name")] public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("draft")] public bool Draft { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("prerelease")] public bool Prerelease { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("published_at")] public DateTime PublishedAt { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("assets")] public List<GitHubReleaseAsset> Assets { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("tarball_url")] public string TarballUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("zipball_url")] public string ZipballUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("body")] public string Body { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileExItem
|
public class ProfileExItem
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
using v2rayN.Base;
|
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileItem
|
public class ProfileItem
|
||||||
@@ -48,16 +47,12 @@ namespace v2rayN.Mode
|
|||||||
}
|
}
|
||||||
switch (configType)
|
switch (configType)
|
||||||
{
|
{
|
||||||
case EConfigType.VMess:
|
case EConfigType.Custom:
|
||||||
case EConfigType.Shadowsocks:
|
summary += string.Format("{0}", remarks);
|
||||||
case EConfigType.Socks:
|
|
||||||
case EConfigType.VLESS:
|
|
||||||
case EConfigType.Trojan:
|
|
||||||
summary += string.Format("{0}({1}:{2})", remarks, addr, port);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
summary += string.Format("{0}", remarks);
|
summary += string.Format("{0}({1}:{2})", remarks, addr, port);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return summary;
|
return summary;
|
||||||
@@ -77,7 +72,7 @@ namespace v2rayN.Mode
|
|||||||
|
|
||||||
public string GetNetwork()
|
public string GetNetwork()
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(network) || !Global.networks.Contains(network))
|
if (Utils.IsNullOrEmpty(network) || !Global.Networks.Contains(network))
|
||||||
{
|
{
|
||||||
return Global.DefaultNetwork;
|
return Global.DefaultNetwork;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileItemModel : ProfileItem
|
public class ProfileItemModel : ProfileItem
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RoutingItem
|
public class RoutingItem
|
||||||
@@ -15,7 +15,9 @@ namespace v2rayN.Mode
|
|||||||
public bool enabled { get; set; } = true;
|
public bool enabled { get; set; } = true;
|
||||||
public bool locked { get; set; }
|
public bool locked { get; set; }
|
||||||
public string customIcon { get; set; }
|
public string customIcon { get; set; }
|
||||||
|
public string customRulesetPath4Singbox { get; set; }
|
||||||
public string domainStrategy { get; set; }
|
public string domainStrategy { get; set; }
|
||||||
|
public string domainStrategy4Singbox { get; set; }
|
||||||
public int sort { get; set; }
|
public int sort { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RoutingItemModel : RoutingItem
|
public class RoutingItemModel : RoutingItem
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RulesItem
|
public class RulesItem
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
public List<string> protocol { get; set; }
|
public List<string> protocol { get; set; }
|
||||||
|
|
||||||
|
public List<string> process { get; set; }
|
||||||
|
|
||||||
public bool enabled { get; set; } = true;
|
public bool enabled { get; set; } = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RulesItemModel : RulesItem
|
public class RulesItemModel : RulesItem
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal class ServerSpeedItem : ServerStatItem
|
internal class ServerSpeedItem : ServerStatItem
|
||||||
@@ -23,4 +23,18 @@
|
|||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class TrafficItem
|
||||||
|
{
|
||||||
|
public ulong up
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong down
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ServerStatItem
|
public class ServerStatItem
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal class ServerTestItem
|
internal class ServerTestItem
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
public class SingboxConfig
|
||||||
|
{
|
||||||
|
public Log4Sbox log { get; set; }
|
||||||
|
public Dns4Sbox? dns { get; set; }
|
||||||
|
public List<Inbound4Sbox> inbounds { get; set; }
|
||||||
|
public List<Outbound4Sbox> outbounds { get; set; }
|
||||||
|
public Route4Sbox route { get; set; }
|
||||||
|
public Experimental4Sbox? experimental { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Log4Sbox
|
||||||
|
{
|
||||||
|
public bool? disabled { get; set; }
|
||||||
|
public string level { get; set; }
|
||||||
|
public string output { get; set; }
|
||||||
|
public bool? timestamp { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Dns4Sbox
|
||||||
|
{
|
||||||
|
public List<Server4Sbox> servers { get; set; }
|
||||||
|
public List<Rule4Sbox> rules { get; set; }
|
||||||
|
public string? final { get; set; }
|
||||||
|
public string? strategy { get; set; }
|
||||||
|
public bool? disable_cache { get; set; }
|
||||||
|
public bool? disable_expire { get; set; }
|
||||||
|
public bool? independent_cache { get; set; }
|
||||||
|
public bool? reverse_mapping { get; set; }
|
||||||
|
public Fakeip4Sbox? fakeip { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Route4Sbox
|
||||||
|
{
|
||||||
|
public bool? auto_detect_interface { get; set; }
|
||||||
|
public List<Rule4Sbox> rules { get; set; }
|
||||||
|
public List<Ruleset4Sbox>? rule_set { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Rule4Sbox
|
||||||
|
{
|
||||||
|
public string? outbound { get; set; }
|
||||||
|
public string? server { get; set; }
|
||||||
|
public bool? disable_cache { get; set; }
|
||||||
|
public List<string>? inbound { get; set; }
|
||||||
|
public List<string>? protocol { get; set; }
|
||||||
|
public string? type { get; set; }
|
||||||
|
public string? mode { get; set; }
|
||||||
|
public string? network { get; set; }
|
||||||
|
public bool? ip_is_private { get; set; }
|
||||||
|
public List<int>? port { get; set; }
|
||||||
|
public List<string>? port_range { get; set; }
|
||||||
|
public List<string>? geosite { get; set; }
|
||||||
|
public List<string>? domain { get; set; }
|
||||||
|
public List<string>? domain_suffix { get; set; }
|
||||||
|
public List<string>? domain_keyword { get; set; }
|
||||||
|
public List<string>? domain_regex { get; set; }
|
||||||
|
public List<string>? geoip { get; set; }
|
||||||
|
public List<string>? ip_cidr { get; set; }
|
||||||
|
public List<string>? source_ip_cidr { get; set; }
|
||||||
|
public List<string>? process_name { get; set; }
|
||||||
|
public List<string>? rule_set { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Inbound4Sbox
|
||||||
|
{
|
||||||
|
public string type { get; set; }
|
||||||
|
public string tag { get; set; }
|
||||||
|
public string listen { get; set; }
|
||||||
|
public int? listen_port { get; set; }
|
||||||
|
public string? domain_strategy { get; set; }
|
||||||
|
public string interface_name { get; set; }
|
||||||
|
public string inet4_address { get; set; }
|
||||||
|
public string? inet6_address { get; set; }
|
||||||
|
public int? mtu { get; set; }
|
||||||
|
public bool? auto_route { get; set; }
|
||||||
|
public bool? strict_route { get; set; }
|
||||||
|
public bool? endpoint_independent_nat { get; set; }
|
||||||
|
public string? stack { get; set; }
|
||||||
|
public bool? sniff { get; set; }
|
||||||
|
public bool? sniff_override_destination { get; set; }
|
||||||
|
public List<User4Sbox> users { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class User4Sbox
|
||||||
|
{
|
||||||
|
public string username { get; set; }
|
||||||
|
public string password { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Outbound4Sbox
|
||||||
|
{
|
||||||
|
public string type { get; set; }
|
||||||
|
public string tag { get; set; }
|
||||||
|
public string? server { get; set; }
|
||||||
|
public int? server_port { get; set; }
|
||||||
|
public string uuid { get; set; }
|
||||||
|
public string security { get; set; }
|
||||||
|
public int? alter_id { get; set; }
|
||||||
|
public string flow { get; set; }
|
||||||
|
public int? up_mbps { get; set; }
|
||||||
|
public int? down_mbps { get; set; }
|
||||||
|
public string auth_str { get; set; }
|
||||||
|
public int? recv_window_conn { get; set; }
|
||||||
|
public int? recv_window { get; set; }
|
||||||
|
public bool? disable_mtu_discovery { get; set; }
|
||||||
|
public string? detour { get; set; }
|
||||||
|
public string method { get; set; }
|
||||||
|
public string username { get; set; }
|
||||||
|
public string password { get; set; }
|
||||||
|
public string congestion_control { get; set; }
|
||||||
|
public string? version { get; set; }
|
||||||
|
public string? network { get; set; }
|
||||||
|
public string? packet_encoding { get; set; }
|
||||||
|
public string[]? local_address { get; set; }
|
||||||
|
public string? private_key { get; set; }
|
||||||
|
public string? peer_public_key { get; set; }
|
||||||
|
public int[]? reserved { get; set; }
|
||||||
|
public int? mtu { get; set; }
|
||||||
|
public string? plugin { get; set; }
|
||||||
|
public string? plugin_opts { get; set; }
|
||||||
|
public Tls4Sbox? tls { get; set; }
|
||||||
|
public Multiplex4Sbox? multiplex { get; set; }
|
||||||
|
public Transport4Sbox? transport { get; set; }
|
||||||
|
public HyObfs4Sbox? obfs { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Tls4Sbox
|
||||||
|
{
|
||||||
|
public bool enabled { get; set; }
|
||||||
|
public string server_name { get; set; }
|
||||||
|
public bool? insecure { get; set; }
|
||||||
|
public List<string> alpn { get; set; }
|
||||||
|
public Utls4Sbox utls { get; set; }
|
||||||
|
public Reality4Sbox reality { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Multiplex4Sbox
|
||||||
|
{
|
||||||
|
public bool enabled { get; set; }
|
||||||
|
public string protocol { get; set; }
|
||||||
|
public int max_connections { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Utls4Sbox
|
||||||
|
{
|
||||||
|
public bool enabled { get; set; }
|
||||||
|
public string fingerprint { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Reality4Sbox
|
||||||
|
{
|
||||||
|
public bool enabled { get; set; }
|
||||||
|
public string public_key { get; set; }
|
||||||
|
public string short_id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Transport4Sbox
|
||||||
|
{
|
||||||
|
public string? type { get; set; }
|
||||||
|
public object? host { get; set; }
|
||||||
|
public string? path { get; set; }
|
||||||
|
public Headers4Sbox? headers { get; set; }
|
||||||
|
|
||||||
|
public string? service_name { get; set; }
|
||||||
|
public string? idle_timeout { get; set; }
|
||||||
|
public string? ping_timeout { get; set; }
|
||||||
|
public bool? permit_without_stream { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Headers4Sbox
|
||||||
|
{
|
||||||
|
public string? Host { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HyObfs4Sbox
|
||||||
|
{
|
||||||
|
public string? type { get; set; }
|
||||||
|
public string? password { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Server4Sbox
|
||||||
|
{
|
||||||
|
public string tag { get; set; }
|
||||||
|
public string address { get; set; }
|
||||||
|
public string address_resolver { get; set; }
|
||||||
|
public string strategy { get; set; }
|
||||||
|
public string? detour { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Experimental4Sbox
|
||||||
|
{
|
||||||
|
public CacheFile4Sbox? cache_file { get; set; }
|
||||||
|
public V2ray_Api4Sbox? v2ray_api { get; set; }
|
||||||
|
public Clash_Api4Sbox? clash_api { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class V2ray_Api4Sbox
|
||||||
|
{
|
||||||
|
public string listen { get; set; }
|
||||||
|
public Stats4Sbox stats { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Clash_Api4Sbox
|
||||||
|
{
|
||||||
|
public string? external_controller { get; set; }
|
||||||
|
public bool? store_selected { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Stats4Sbox
|
||||||
|
{
|
||||||
|
public bool enabled { get; set; }
|
||||||
|
public List<string>? inbounds { get; set; }
|
||||||
|
public List<string>? outbounds { get; set; }
|
||||||
|
public List<string>? users { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Fakeip4Sbox
|
||||||
|
{
|
||||||
|
public bool enabled { get; set; }
|
||||||
|
public string inet4_range { get; set; }
|
||||||
|
public string inet6_range { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CacheFile4Sbox
|
||||||
|
{
|
||||||
|
public bool enabled { get; set; }
|
||||||
|
public string? path { get; set; }
|
||||||
|
public string? cache_id { get; set; }
|
||||||
|
public bool? store_fakeip { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Ruleset4Sbox
|
||||||
|
{
|
||||||
|
public string? tag { get; set; }
|
||||||
|
public string? type { get; set; }
|
||||||
|
public string? format { get; set; }
|
||||||
|
public string? path { get; set; }
|
||||||
|
public string? url { get; set; }
|
||||||
|
public string? download_detour { get; set; }
|
||||||
|
public string? update_interval { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
public class SsSIP008
|
public class SsSIP008
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class SubItem
|
public class SubItem
|
||||||
@@ -27,5 +27,9 @@ namespace v2rayN.Mode
|
|||||||
public long updateTime { get; set; }
|
public long updateTime { get; set; }
|
||||||
|
|
||||||
public string? convertTarget { get; set; }
|
public string? convertTarget { get; set; }
|
||||||
|
|
||||||
|
public string? prevProfile { get; set; }
|
||||||
|
|
||||||
|
public string? nextProfile { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
internal class SysproxyConfig
|
internal class SysProxyConfig
|
||||||
{
|
{
|
||||||
public bool UserSettingsRecorded;
|
public bool UserSettingsRecorded;
|
||||||
public string Flags;
|
public string Flags;
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
public string BypassList;
|
public string BypassList;
|
||||||
public string PacUrl;
|
public string PacUrl;
|
||||||
|
|
||||||
public SysproxyConfig()
|
public SysProxyConfig()
|
||||||
{
|
{
|
||||||
UserSettingsRecorded = false;
|
UserSettingsRecorded = false;
|
||||||
Flags = "1";
|
Flags = "1";
|
||||||
@@ -1,38 +1,42 @@
|
|||||||
using Newtonsoft.Json;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// v2ray配置文件实体类
|
/// v2ray配置文件实体类 例子SampleConfig.txt
|
||||||
/// 例子SampleConfig.txt
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class V2rayConfig
|
public class V2rayConfig
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Properties that do not belong to Ray
|
||||||
|
/// </summary>
|
||||||
|
public string? remarks { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 日志配置
|
/// 日志配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Log log { get; set; }
|
public Log4Ray log { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 传入连接配置
|
/// 传入连接配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<Inbounds> inbounds { get; set; }
|
public List<Inbounds4Ray> inbounds { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 传出连接配置
|
/// 传出连接配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<Outbounds> outbounds { get; set; }
|
public List<Outbounds4Ray> outbounds { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 统计需要, 空对象
|
/// 统计需要, 空对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Stats stats { get; set; }
|
public Stats4Ray stats { get; set; }
|
||||||
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public API api { get; set; }
|
public API4Ray api { get; set; }
|
||||||
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Policy policy;
|
public Policy4Ray policy { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DNS 配置
|
/// DNS 配置
|
||||||
@@ -42,30 +46,30 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 路由配置
|
/// 路由配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Routing routing { get; set; }
|
public Routing4Ray routing { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Stats
|
public class Stats4Ray
|
||||||
{ };
|
{ };
|
||||||
|
|
||||||
public class API
|
public class API4Ray
|
||||||
{
|
{
|
||||||
public string tag { get; set; }
|
public string tag { get; set; }
|
||||||
public List<string> services { get; set; }
|
public List<string> services { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Policy
|
public class Policy4Ray
|
||||||
{
|
{
|
||||||
public SystemPolicy system;
|
public SystemPolicy4Ray system { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SystemPolicy
|
public class SystemPolicy4Ray
|
||||||
{
|
{
|
||||||
public bool statsOutboundUplink;
|
public bool statsOutboundUplink { get; set; }
|
||||||
public bool statsOutboundDownlink;
|
public bool statsOutboundDownlink { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Log
|
public class Log4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -83,7 +87,7 @@ namespace v2rayN.Mode
|
|||||||
public string loglevel { get; set; }
|
public string loglevel { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Inbounds
|
public class Inbounds4Ray
|
||||||
{
|
{
|
||||||
public string tag { get; set; }
|
public string tag { get; set; }
|
||||||
|
|
||||||
@@ -105,20 +109,20 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Sniffing sniffing { get; set; }
|
public Sniffing4Ray sniffing { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Inboundsettings settings { get; set; }
|
public Inboundsettings4Ray settings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StreamSettings streamSettings { get; set; }
|
public StreamSettings4Ray streamSettings { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Inboundsettings
|
public class Inboundsettings4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -143,7 +147,7 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<UsersItem> clients { get; set; }
|
public List<UsersItem4Ray> clients { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// VLESS
|
/// VLESS
|
||||||
@@ -152,10 +156,10 @@ namespace v2rayN.Mode
|
|||||||
|
|
||||||
public bool allowTransparent { get; set; }
|
public bool allowTransparent { get; set; }
|
||||||
|
|
||||||
public List<AccountsItem> accounts { get; set; }
|
public List<AccountsItem4Ray> accounts { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UsersItem
|
public class UsersItem4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -185,17 +189,17 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// VLESS
|
/// VLESS
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string flow { get; set; }
|
public string? flow { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Sniffing
|
public class Sniffing4Ray
|
||||||
{
|
{
|
||||||
public bool enabled { get; set; }
|
public bool enabled { get; set; }
|
||||||
public List<string> destOverride { get; set; }
|
public List<string>? destOverride { get; set; }
|
||||||
public bool routeOnly { get; set; }
|
public bool routeOnly { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Outbounds
|
public class Outbounds4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 默认值agentout
|
/// 默认值agentout
|
||||||
@@ -210,35 +214,35 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Outboundsettings settings { get; set; }
|
public Outboundsettings4Ray settings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StreamSettings streamSettings { get; set; }
|
public StreamSettings4Ray streamSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Mux mux { get; set; }
|
public Mux4Ray mux { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Outboundsettings
|
public class Outboundsettings4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<VnextItem> vnext { get; set; }
|
public List<VnextItem4Ray>? vnext { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<ServersItem> servers { get; set; }
|
public List<ServersItem4Ray> servers { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Response response { get; set; }
|
public Response4Ray response { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -249,9 +253,11 @@ namespace v2rayN.Mode
|
|||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? userLevel { get; set; }
|
public int? userLevel { get; set; }
|
||||||
|
|
||||||
|
public FragmentItem4Ray? fragment { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VnextItem
|
public class VnextItem4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -266,10 +272,10 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<UsersItem> users { get; set; }
|
public List<UsersItem4Ray> users { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ServersItem
|
public class ServersItem4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -284,17 +290,17 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string method { get; set; }
|
public string? method { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ota { get; set; }
|
public bool? ota { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string password { get; set; }
|
public string? password { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -304,7 +310,7 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int level { get; set; }
|
public int? level { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// trojan
|
/// trojan
|
||||||
@@ -314,10 +320,10 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<SocksUsersItem> users { get; set; }
|
public List<SocksUsersItem4Ray> users { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SocksUsersItem
|
public class SocksUsersItem4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -332,10 +338,10 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int level { get; set; }
|
public int? level { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Mux
|
public class Mux4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -348,7 +354,7 @@ namespace v2rayN.Mode
|
|||||||
public int concurrency { get; set; }
|
public int concurrency { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Response
|
public class Response4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -356,7 +362,7 @@ namespace v2rayN.Mode
|
|||||||
public string type { get; set; }
|
public string type { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Dns
|
public class Dns4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -364,7 +370,7 @@ namespace v2rayN.Mode
|
|||||||
public List<string> servers { get; set; }
|
public List<string> servers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Routing
|
public class Routing4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -379,10 +385,28 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<RulesItem> rules { get; set; }
|
public List<RulesItem4Ray> rules { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StreamSettings
|
[Serializable]
|
||||||
|
public class RulesItem4Ray
|
||||||
|
{
|
||||||
|
public string? type { get; set; }
|
||||||
|
|
||||||
|
public string? port { get; set; }
|
||||||
|
|
||||||
|
public List<string>? inboundTag { get; set; }
|
||||||
|
|
||||||
|
public string? outboundTag { get; set; }
|
||||||
|
|
||||||
|
public List<string>? ip { get; set; }
|
||||||
|
|
||||||
|
public List<string>? domain { get; set; }
|
||||||
|
|
||||||
|
public List<string>? protocol { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StreamSettings4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -397,45 +421,55 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TlsSettings tlsSettings { get; set; }
|
public TlsSettings4Ray tlsSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tcp传输额外设置
|
/// Tcp传输额外设置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TcpSettings tcpSettings { get; set; }
|
public TcpSettings4Ray tcpSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Kcp传输额外设置
|
/// Kcp传输额外设置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public KcpSettings kcpSettings { get; set; }
|
public KcpSettings4Ray kcpSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ws传输额外设置
|
/// ws传输额外设置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public WsSettings wsSettings { get; set; }
|
public WsSettings4Ray wsSettings { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// h2传输额外设置
|
/// h2传输额外设置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HttpSettings httpSettings { get; set; }
|
public HttpSettings4Ray httpSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// QUIC
|
/// QUIC
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public QuicSettings quicSettings { get; set; }
|
public QuicSettings4Ray quicSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// VLESS only
|
/// VLESS only
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TlsSettings realitySettings { get; set; }
|
public TlsSettings4Ray realitySettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// grpc
|
/// grpc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GrpcSettings grpcSettings { get; set; }
|
public GrpcSettings4Ray grpcSettings { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// sockopt
|
||||||
|
/// </summary>
|
||||||
|
public Sockopt4Ray? sockopt { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TlsSettings
|
public class TlsSettings4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否允许不安全连接(用于客户端)
|
/// 是否允许不安全连接(用于客户端)
|
||||||
@@ -460,15 +494,15 @@ namespace v2rayN.Mode
|
|||||||
public string? spiderX { get; set; }
|
public string? spiderX { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TcpSettings
|
public class TcpSettings4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 数据包头部伪装设置
|
/// 数据包头部伪装设置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Header header { get; set; }
|
public Header4Ray header { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Header
|
public class Header4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 伪装
|
/// 伪装
|
||||||
@@ -486,7 +520,7 @@ namespace v2rayN.Mode
|
|||||||
public object response { get; set; }
|
public object response { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class KcpSettings
|
public class KcpSettings4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -526,7 +560,7 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Header header { get; set; }
|
public Header4Ray header { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -534,7 +568,7 @@ namespace v2rayN.Mode
|
|||||||
public string seed { get; set; }
|
public string seed { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WsSettings
|
public class WsSettings4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -544,10 +578,10 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Headers headers { get; set; }
|
public Headers4Ray headers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Headers
|
public class Headers4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -557,11 +591,24 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用户代理
|
/// 用户代理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("User-Agent")]
|
[JsonPropertyName("User-Agent")]
|
||||||
public string UserAgent { get; set; }
|
public string UserAgent { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HttpSettings
|
public class HttpupgradeSettings4Ray
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string? path { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string? host { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HttpSettings4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -574,7 +621,7 @@ namespace v2rayN.Mode
|
|||||||
public List<string> host { get; set; }
|
public List<string> host { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class QuicSettings
|
public class QuicSettings4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -589,12 +636,13 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Header header { get; set; }
|
public Header4Ray header { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GrpcSettings
|
public class GrpcSettings4Ray
|
||||||
{
|
{
|
||||||
public string serviceName { get; set; }
|
public string? authority { get; set; }
|
||||||
|
public string? serviceName { get; set; }
|
||||||
public bool multiMode { get; set; }
|
public bool multiMode { get; set; }
|
||||||
public int idle_timeout { get; set; }
|
public int idle_timeout { get; set; }
|
||||||
public int health_check_timeout { get; set; }
|
public int health_check_timeout { get; set; }
|
||||||
@@ -602,7 +650,7 @@ namespace v2rayN.Mode
|
|||||||
public int initial_windows_size { get; set; }
|
public int initial_windows_size { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AccountsItem
|
public class AccountsItem4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -614,4 +662,16 @@ namespace v2rayN.Mode
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string pass { get; set; }
|
public string pass { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Sockopt4Ray
|
||||||
|
{
|
||||||
|
public string? dialerProxy { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FragmentItem4Ray
|
||||||
|
{
|
||||||
|
public string? packets { get; set; }
|
||||||
|
public string? length { get; set; }
|
||||||
|
public string? interval { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace v2rayN.Models
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tcp伪装http的Request,只要Host
|
/// Tcp伪装http的Request,只要Host
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace v2rayN.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// https://github.com/2dust/v2rayN/wiki/
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
internal class VmessQRCode
|
||||||
|
{
|
||||||
|
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||||
|
public int v { get; set; } = 2;
|
||||||
|
|
||||||
|
public string ps { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string add { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||||
|
public int port { get; set; } = 0;
|
||||||
|
|
||||||
|
public string id { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||||
|
public int aid { get; set; } = 0;
|
||||||
|
|
||||||
|
public string scy { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string net { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string type { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string host { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string path { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string tls { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string sni { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string alpn { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string fp { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
-20
@@ -219,25 +219,5 @@ namespace v2rayN.Properties {
|
|||||||
return ((System.Drawing.Bitmap)(obj));
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找 System.Byte[] 类型的本地化资源。
|
|
||||||
/// </summary>
|
|
||||||
internal static byte[] sysproxy_exe {
|
|
||||||
get {
|
|
||||||
object obj = ResourceManager.GetObject("sysproxy_exe", resourceCulture);
|
|
||||||
return ((byte[])(obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找 System.Byte[] 类型的本地化资源。
|
|
||||||
/// </summary>
|
|
||||||
internal static byte[] sysproxy64_exe {
|
|
||||||
get {
|
|
||||||
object obj = ResourceManager.GetObject("sysproxy64_exe", resourceCulture);
|
|
||||||
return ((byte[])(obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,12 +118,6 @@
|
|||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
<data name="sysproxy_exe" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
|
||||||
<value>..\resources\sysproxy.exe.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</data>
|
|
||||||
<data name="sysproxy64_exe" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
|
||||||
<value>..\resources\sysproxy64.exe.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</data>
|
|
||||||
<data name="NotifyIcon1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="NotifyIcon1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\NotifyIcon1.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\NotifyIcon1.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Generated
+393
-96
File diff suppressed because it is too large
Load Diff
@@ -187,10 +187,10 @@
|
|||||||
<value>پیکربندی اولیه</value>
|
<value>پیکربندی اولیه</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestCore" xml:space="preserve">
|
<data name="IsLatestCore" xml:space="preserve">
|
||||||
<value>{0} در حال حاضر به روز است.</value>
|
<value>{0} {1} در حال حاضر به روز است.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestN" xml:space="preserve">
|
<data name="IsLatestN" xml:space="preserve">
|
||||||
<value>{0} در حال حاضر به روز است.</value>
|
<value>{0} {1} در حال حاضر به روز است.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvAddress" xml:space="preserve">
|
<data name="LvAddress" xml:space="preserve">
|
||||||
<value>آدرس</value>
|
<value>آدرس</value>
|
||||||
@@ -300,9 +300,6 @@
|
|||||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||||
<value>The client configuration file is saved at: {0}</value>
|
<value>The client configuration file is saved at: {0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SaveServerConfigurationIn" xml:space="preserve">
|
|
||||||
<value>The server configuration file is saved at: {0}</value>
|
|
||||||
</data>
|
|
||||||
<data name="StartService" xml:space="preserve">
|
<data name="StartService" xml:space="preserve">
|
||||||
<value>Start service ({0})...</value>
|
<value>Start service ({0})...</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -532,9 +529,6 @@
|
|||||||
<data name="menuClearServerStatistics" xml:space="preserve">
|
<data name="menuClearServerStatistics" xml:space="preserve">
|
||||||
<value>تمام آمار خدمات را پاک کنید</value>
|
<value>تمام آمار خدمات را پاک کنید</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuPingServer" xml:space="preserve">
|
|
||||||
<value>تست پینگ سرورها (Ctrl+P)</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRealPingServer" xml:space="preserve">
|
<data name="menuRealPingServer" xml:space="preserve">
|
||||||
<value>آزمایش سرورها با تاخیر واقعی (Ctrl+R)</value>
|
<value>آزمایش سرورها با تاخیر واقعی (Ctrl+R)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -553,9 +547,6 @@
|
|||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>سرور انتخابی را برای پیکربندی کلاینت صادر کنید</value>
|
<value>سرور انتخابی را برای پیکربندی کلاینت صادر کنید</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ServerConfig" xml:space="preserve">
|
|
||||||
<value>سرور انتخاب شده را برای پیکربندی سرور صادر کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>URL های اشتراک گذاری را به کلیپ بورد صادر کنید (Ctrl+C)</value>
|
<value>URL های اشتراک گذاری را به کلیپ بورد صادر کنید (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -707,7 +698,7 @@
|
|||||||
<value>txtPreSocksPort</value>
|
<value>txtPreSocksPort</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipPreSocksPort" xml:space="preserve">
|
<data name="TipPreSocksPort" xml:space="preserve">
|
||||||
<value>* After setting this value, an socks service will be started using V2ray to provide functions such as speed display</value>
|
<value>* After setting this value, an socks service will be started using Xray/sing-box(Tun) to provide functions such as speed display</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbBrowse" xml:space="preserve">
|
<data name="TbBrowse" xml:space="preserve">
|
||||||
<value>Browse</value>
|
<value>Browse</value>
|
||||||
@@ -731,7 +722,7 @@
|
|||||||
<value>هسته: تنظیمات اولیه</value>
|
<value>هسته: تنظیمات اولیه</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCoreDns" xml:space="preserve">
|
<data name="TbSettingsCoreDns" xml:space="preserve">
|
||||||
<value>هسته: تنظیمات DNS</value>
|
<value>V2ray DNS settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
||||||
<value>هسته: تنظیمات KCP</value>
|
<value>هسته: تنظیمات KCP</value>
|
||||||
@@ -799,9 +790,6 @@
|
|||||||
<data name="TbSettingsStatistics" xml:space="preserve">
|
<data name="TbSettingsStatistics" xml:space="preserve">
|
||||||
<value>فعال کردن آمار (نیاز به راه اندازی مجدد)</value>
|
<value>فعال کردن آمار (نیاز به راه اندازی مجدد)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStatisticsFreshRate" xml:space="preserve">
|
|
||||||
<value>نرخ تازه سازی آمار (ثانیه)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsSubConvert" xml:space="preserve">
|
<data name="TbSettingsSubConvert" xml:space="preserve">
|
||||||
<value>Subscription conversion Url</value>
|
<value>Subscription conversion Url</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1015,4 +1003,7 @@
|
|||||||
<data name="TbSettingsEnableHWA" xml:space="preserve">
|
<data name="TbSettingsEnableHWA" xml:space="preserve">
|
||||||
<value>فعالسازی شتابدهنده سختافزاری (نیاز به راهاندازی مجدد)</value>
|
<value>فعالسازی شتابدهنده سختافزاری (نیاز به راهاندازی مجدد)</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
||||||
|
<value>فعال کردن کش فایل مجموعه قوانین برای sing-box</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
+169
-70
@@ -148,7 +148,7 @@
|
|||||||
<value>Failed to generate default configuration file</value>
|
<value>Failed to generate default configuration file</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
|
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
|
||||||
<value> Failed to get the default configuration</value>
|
<value>Failed to get the default configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedImportedCustomServer" xml:space="preserve">
|
<data name="FailedImportedCustomServer" xml:space="preserve">
|
||||||
<value>Failed to import custom configuration server</value>
|
<value>Failed to import custom configuration server</value>
|
||||||
@@ -175,22 +175,22 @@
|
|||||||
<value>Please fill in the user ID</value>
|
<value>Please fill in the user ID</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectClientConfiguration" xml:space="preserve">
|
<data name="IncorrectClientConfiguration" xml:space="preserve">
|
||||||
<value> is not the correct client configuration file, please check</value>
|
<value>Is not the correct client configuration file, please check</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||||
<value> is not the correct configuration, please check</value>
|
<value>Is not the correct configuration, please check</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectServerConfiguration" xml:space="preserve">
|
<data name="IncorrectServerConfiguration" xml:space="preserve">
|
||||||
<value> is not the correct server configuration file, please check</value>
|
<value>Is not the correct server configuration file, please check</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="InitialConfiguration" xml:space="preserve">
|
<data name="InitialConfiguration" xml:space="preserve">
|
||||||
<value>Initial Configuration</value>
|
<value>Initial Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestCore" xml:space="preserve">
|
<data name="IsLatestCore" xml:space="preserve">
|
||||||
<value>{0} already up to date.</value>
|
<value>{0} {1} already up to date.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestN" xml:space="preserve">
|
<data name="IsLatestN" xml:space="preserve">
|
||||||
<value>{0} already up to date.</value>
|
<value>{0} {1} already up to date.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvAddress" xml:space="preserve">
|
<data name="LvAddress" xml:space="preserve">
|
||||||
<value>Address</value>
|
<value>Address</value>
|
||||||
@@ -250,7 +250,7 @@
|
|||||||
<value>Invalid subscription content</value>
|
<value>Invalid subscription content</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgUnpacking" xml:space="preserve">
|
<data name="MsgUnpacking" xml:space="preserve">
|
||||||
<value>is unpacking...</value>
|
<value>Is unpacking......</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgUpdateSubscriptionEnd" xml:space="preserve">
|
<data name="MsgUpdateSubscriptionEnd" xml:space="preserve">
|
||||||
<value>Update subscription end</value>
|
<value>Update subscription end</value>
|
||||||
@@ -268,7 +268,7 @@
|
|||||||
<value>Non-VMess or ss protocol</value>
|
<value>Non-VMess or ss protocol</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NonVmessService" xml:space="preserve">
|
<data name="NonVmessService" xml:space="preserve">
|
||||||
<value> non-standard service, this feature is invalid</value>
|
<value>Non-standard service, this feature is invalid</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NotFoundCore" xml:space="preserve">
|
<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>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>
|
||||||
@@ -277,7 +277,7 @@
|
|||||||
<value>Scan completed, no valid QR code found</value>
|
<value>Scan completed, no valid QR code found</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="OperationFailed" xml:space="preserve">
|
<data name="OperationFailed" xml:space="preserve">
|
||||||
<value> operation failed, please check and retry</value>
|
<value>Operation failed, please check and retry</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseFillRemarks" xml:space="preserve">
|
<data name="PleaseFillRemarks" xml:space="preserve">
|
||||||
<value>Please Fill Remarks</value>
|
<value>Please Fill Remarks</value>
|
||||||
@@ -300,9 +300,6 @@
|
|||||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||||
<value>The client configuration file is saved at: {0}</value>
|
<value>The client configuration file is saved at: {0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SaveServerConfigurationIn" xml:space="preserve">
|
|
||||||
<value>The server configuration file is saved at: {0}</value>
|
|
||||||
</data>
|
|
||||||
<data name="StartService" xml:space="preserve">
|
<data name="StartService" xml:space="preserve">
|
||||||
<value>Start service ({0})...</value>
|
<value>Start service ({0})...</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -311,10 +308,10 @@
|
|||||||
{0}</value>
|
{0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
||||||
<value>Custom configuration server imported successfully.</value>
|
<value>Custom configuration server imported successfully</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
||||||
<value>{0} servers have been imported from clipboard.</value>
|
<value>{0} servers have been imported from clipboard</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
||||||
<value>Scan import URL successfully</value>
|
<value>Scan import URL successfully</value>
|
||||||
@@ -338,13 +335,13 @@
|
|||||||
<value>Remarks</value>
|
<value>Remarks</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvUrl" xml:space="preserve">
|
<data name="LvUrl" xml:space="preserve">
|
||||||
<value>Url(Optional)</value>
|
<value>URL(Optional)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvCount" xml:space="preserve">
|
<data name="LvCount" xml:space="preserve">
|
||||||
<value>Count</value>
|
<value>Count</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgNeedUrl" xml:space="preserve">
|
<data name="MsgNeedUrl" xml:space="preserve">
|
||||||
<value>Please fill in the Url</value>
|
<value>Please fill in the URL</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AddBatchRoutingRulesYesNo" xml:space="preserve">
|
<data name="AddBatchRoutingRulesYesNo" xml:space="preserve">
|
||||||
<value>Do you want to append rules? Choose yes to append, choose otherwise to replace</value>
|
<value>Do you want to append rules? Choose yes to append, choose otherwise to replace</value>
|
||||||
@@ -362,13 +359,13 @@
|
|||||||
<value>Please fill in the correct custom DNS</value>
|
<value>Please fill in the correct custom DNS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip1" xml:space="preserve">
|
<data name="TransportPathTip1" xml:space="preserve">
|
||||||
<value>*ws path</value>
|
<value>*ws/httpupgrade path</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip2" xml:space="preserve">
|
<data name="TransportPathTip2" xml:space="preserve">
|
||||||
<value>*h2 path</value>
|
<value>*h2 path</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip3" xml:space="preserve">
|
<data name="TransportPathTip3" xml:space="preserve">
|
||||||
<value>*QUIC key/Kcp seed</value>
|
<value>*QUIC key/KCP seed</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip4" xml:space="preserve">
|
<data name="TransportPathTip4" xml:space="preserve">
|
||||||
<value>*grpc serviceName</value>
|
<value>*grpc serviceName</value>
|
||||||
@@ -377,7 +374,7 @@
|
|||||||
<value>*http host Separated by commas (,)</value>
|
<value>*http host Separated by commas (,)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip2" xml:space="preserve">
|
<data name="TransportRequestHostTip2" xml:space="preserve">
|
||||||
<value>*ws host</value>
|
<value>*ws/httpupgrade host</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip3" xml:space="preserve">
|
<data name="TransportRequestHostTip3" xml:space="preserve">
|
||||||
<value>*h2 host Separated by commas (,)</value>
|
<value>*h2 host Separated by commas (,)</value>
|
||||||
@@ -401,7 +398,7 @@
|
|||||||
<value>TLS</value>
|
<value>TLS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip5" xml:space="preserve">
|
<data name="TransportPathTip5" xml:space="preserve">
|
||||||
<value>*Kcp seed</value>
|
<value>*kcp seed</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RegisterGlobalHotkeyFailed" xml:space="preserve">
|
<data name="RegisterGlobalHotkeyFailed" xml:space="preserve">
|
||||||
<value>Global hotkey {0} registered failed, reason {1}</value>
|
<value>Global hotkey {0} registered failed, reason {1}</value>
|
||||||
@@ -446,13 +443,13 @@
|
|||||||
<value>Exit</value>
|
<value>Exit</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuGlobalHotkeySetting" xml:space="preserve">
|
<data name="menuGlobalHotkeySetting" xml:space="preserve">
|
||||||
<value>GlobalHotkeySetting</value>
|
<value>Global Hotkey Setting</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuHelp" xml:space="preserve">
|
<data name="menuHelp" xml:space="preserve">
|
||||||
<value>Help</value>
|
<value>Help</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuOptionSetting" xml:space="preserve">
|
<data name="menuOptionSetting" xml:space="preserve">
|
||||||
<value>OptionSetting</value>
|
<value>Option Setting</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuPromotion" xml:space="preserve">
|
<data name="menuPromotion" xml:space="preserve">
|
||||||
<value>Promotion</value>
|
<value>Promotion</value>
|
||||||
@@ -461,7 +458,7 @@
|
|||||||
<value>Reload</value>
|
<value>Reload</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingSetting" xml:space="preserve">
|
<data name="menuRoutingSetting" xml:space="preserve">
|
||||||
<value>RoutingSetting</value>
|
<value>Routing Setting</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuServers" xml:space="preserve">
|
<data name="menuServers" xml:space="preserve">
|
||||||
<value>Servers</value>
|
<value>Servers</value>
|
||||||
@@ -479,7 +476,7 @@
|
|||||||
<value>Subscription group</value>
|
<value>Subscription group</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSubSetting" xml:space="preserve">
|
<data name="menuSubSetting" xml:space="preserve">
|
||||||
<value>Subscription group Settings</value>
|
<value>Subscription group settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSubUpdate" xml:space="preserve">
|
<data name="menuSubUpdate" xml:space="preserve">
|
||||||
<value>Update subscription without proxy</value>
|
<value>Update subscription without proxy</value>
|
||||||
@@ -497,7 +494,7 @@
|
|||||||
<value>Do not change system proxy</value>
|
<value>Do not change system proxy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSystemProxyPac" xml:space="preserve">
|
<data name="menuSystemProxyPac" xml:space="preserve">
|
||||||
<value>Pac Mode</value>
|
<value>PAC mode</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSystemProxySet" xml:space="preserve">
|
<data name="menuSystemProxySet" xml:space="preserve">
|
||||||
<value>Set system proxy</value>
|
<value>Set system proxy</value>
|
||||||
@@ -508,8 +505,11 @@
|
|||||||
<data name="TbSettingsColorMode" xml:space="preserve">
|
<data name="TbSettingsColorMode" xml:space="preserve">
|
||||||
<value>Dark Mode</value>
|
<value>Dark Mode</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
|
||||||
|
<value>Follow System Theme</value>
|
||||||
|
</data>
|
||||||
<data name="TbSettingsLanguage" xml:space="preserve">
|
<data name="TbSettingsLanguage" xml:space="preserve">
|
||||||
<value>Language(Restart)</value>
|
<value>Language (Restart)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
||||||
<value>Import bulk URL from clipboard (Ctrl+V)</value>
|
<value>Import bulk URL from clipboard (Ctrl+V)</value>
|
||||||
@@ -532,9 +532,6 @@
|
|||||||
<data name="menuClearServerStatistics" xml:space="preserve">
|
<data name="menuClearServerStatistics" xml:space="preserve">
|
||||||
<value>Clear all service statistics</value>
|
<value>Clear all service statistics</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuPingServer" xml:space="preserve">
|
|
||||||
<value>Test servers ping (Ctrl+P)</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRealPingServer" xml:space="preserve">
|
<data name="menuRealPingServer" xml:space="preserve">
|
||||||
<value>Test servers real delay (Ctrl+R)</value>
|
<value>Test servers real delay (Ctrl+R)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -553,9 +550,6 @@
|
|||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>Export selected server for client configuration</value>
|
<value>Export selected server for client configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ServerConfig" xml:space="preserve">
|
|
||||||
<value>Export selected server for server configuration</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>Export share URLs to clipboard (Ctrl+C)</value>
|
<value>Export share URLs to clipboard (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -581,22 +575,22 @@
|
|||||||
<value>Add [VMess] server</value>
|
<value>Add [VMess] server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSelectAll" xml:space="preserve">
|
<data name="menuSelectAll" xml:space="preserve">
|
||||||
<value>Select All (Ctrl+A)</value>
|
<value>Select all (Ctrl+A)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMsgViewClear" xml:space="preserve">
|
<data name="menuMsgViewClear" xml:space="preserve">
|
||||||
<value>Clear All</value>
|
<value>Clear all</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMsgViewCopy" xml:space="preserve">
|
<data name="menuMsgViewCopy" xml:space="preserve">
|
||||||
<value>Copy (Ctrl+C)</value>
|
<value>Copy (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
||||||
<value>Copy All</value>
|
<value>Copy all</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMsgViewFilter" xml:space="preserve">
|
<data name="menuMsgViewFilter" xml:space="preserve">
|
||||||
<value>Set message filters</value>
|
<value>Set message filters</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
||||||
<value>Select All (Ctrl+A)</value>
|
<value>Select all (Ctrl+A)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSubAdd" xml:space="preserve">
|
<data name="menuSubAdd" xml:space="preserve">
|
||||||
<value>Add</value>
|
<value>Add</value>
|
||||||
@@ -635,10 +629,10 @@
|
|||||||
<value>AllowInsecure</value>
|
<value>AllowInsecure</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAlpn" xml:space="preserve">
|
<data name="TbAlpn" xml:space="preserve">
|
||||||
<value>Alpn</value>
|
<value>ALPN</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAlterId" xml:space="preserve">
|
<data name="TbAlterId" xml:space="preserve">
|
||||||
<value>AlterId</value>
|
<value>AlterID</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFingerprint" xml:space="preserve">
|
<data name="TbFingerprint" xml:space="preserve">
|
||||||
<value>Fingerprint</value>
|
<value>Fingerprint</value>
|
||||||
@@ -707,7 +701,7 @@
|
|||||||
<value>txtPreSocksPort</value>
|
<value>txtPreSocksPort</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipPreSocksPort" xml:space="preserve">
|
<data name="TipPreSocksPort" xml:space="preserve">
|
||||||
<value>* After setting this value, an socks service will be started using V2ray to provide functions such as speed display</value>
|
<value>* After setting this value, an socks service will be started using Xray/sing-box(Tun) to provide functions such as speed display</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbBrowse" xml:space="preserve">
|
<data name="TbBrowse" xml:space="preserve">
|
||||||
<value>Browse</value>
|
<value>Browse</value>
|
||||||
@@ -725,13 +719,13 @@
|
|||||||
<value>Auto hide startup</value>
|
<value>Auto hide startup</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
|
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
|
||||||
<value>Automatic update interval of and Geo (hours)</value>
|
<value>Automatic update interval of Geo (hours)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCore" xml:space="preserve">
|
<data name="TbSettingsCore" xml:space="preserve">
|
||||||
<value>Core: basic settings</value>
|
<value>Core: basic settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCoreDns" xml:space="preserve">
|
<data name="TbSettingsCoreDns" xml:space="preserve">
|
||||||
<value>Core: DNS settings</value>
|
<value>V2ray DNS settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
||||||
<value>Core: KCP settings</value>
|
<value>Core: KCP settings</value>
|
||||||
@@ -758,7 +752,7 @@
|
|||||||
<value>Exception. Do not use proxy server for addresses beginning with,Use semicolon (;)</value>
|
<value>Exception. Do not use proxy server for addresses beginning with,Use semicolon (;)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
<data name="TbSettingsHttpPort" xml:space="preserve">
|
||||||
<value>Http Port</value>
|
<value>HTTP Port</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
|
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
|
||||||
<value>Ignore Geo files when updating core</value>
|
<value>Ignore Geo files when updating core</value>
|
||||||
@@ -791,7 +785,7 @@
|
|||||||
<value>Turn on Sniffing</value>
|
<value>Turn on Sniffing</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPort" xml:space="preserve">
|
<data name="TbSettingsSocksPort" xml:space="preserve">
|
||||||
<value>Socks Port</value>
|
<value>SOCKS Port</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStartBoot" xml:space="preserve">
|
<data name="TbSettingsStartBoot" xml:space="preserve">
|
||||||
<value>Start on boot</value>
|
<value>Start on boot</value>
|
||||||
@@ -799,11 +793,8 @@
|
|||||||
<data name="TbSettingsStatistics" xml:space="preserve">
|
<data name="TbSettingsStatistics" xml:space="preserve">
|
||||||
<value>Enable Statistics (Require restart)</value>
|
<value>Enable Statistics (Require restart)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStatisticsFreshRate" xml:space="preserve">
|
|
||||||
<value>Statistics freshrate (second)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsSubConvert" xml:space="preserve">
|
<data name="TbSettingsSubConvert" xml:space="preserve">
|
||||||
<value>Subscription conversion Url</value>
|
<value>Subscription conversion URL</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSystemproxy" xml:space="preserve">
|
<data name="TbSettingsSystemproxy" xml:space="preserve">
|
||||||
<value>System proxy settings</value>
|
<value>System proxy settings</value>
|
||||||
@@ -827,10 +818,10 @@
|
|||||||
<value>Display GUI</value>
|
<value>Display GUI</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbGlobalHotkeySetting" xml:space="preserve">
|
<data name="TbGlobalHotkeySetting" xml:space="preserve">
|
||||||
<value>GlobalHotkey Settings</value>
|
<value>Global Hotkey Settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbGlobalHotkeySettingTip" xml:space="preserve">
|
<data name="TbGlobalHotkeySettingTip" xml:space="preserve">
|
||||||
<value>Set directly by pressing the keyboard, Take effect after restart</value>
|
<value>Set directly by pressing the keyboard, take effect after restart</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbNotChangeSystemProxy" xml:space="preserve">
|
<data name="TbNotChangeSystemProxy" xml:space="preserve">
|
||||||
<value>Do not change system proxy</value>
|
<value>Do not change system proxy</value>
|
||||||
@@ -842,7 +833,7 @@
|
|||||||
<value>Set system proxy</value>
|
<value>Set system proxy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSystemProxyPac" xml:space="preserve">
|
<data name="TbSystemProxyPac" xml:space="preserve">
|
||||||
<value>Pac Mode</value>
|
<value>PAC mode</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuShareServer" xml:space="preserve">
|
<data name="menuShareServer" xml:space="preserve">
|
||||||
<value>Share Server (Ctrl+F)</value>
|
<value>Share Server (Ctrl+F)</value>
|
||||||
@@ -851,10 +842,10 @@
|
|||||||
<value>Routing</value>
|
<value>Routing</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NotRunAsAdmin" xml:space="preserve">
|
<data name="NotRunAsAdmin" xml:space="preserve">
|
||||||
<value>Not Run As Admin</value>
|
<value>Not run as Admin</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RunAsAdmin" xml:space="preserve">
|
<data name="RunAsAdmin" xml:space="preserve">
|
||||||
<value>Run As Admin</value>
|
<value>Run as Admin</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMoveBottom" xml:space="preserve">
|
<data name="menuMoveBottom" xml:space="preserve">
|
||||||
<value>Move to bottom (B)</value>
|
<value>Move to bottom (B)</value>
|
||||||
@@ -884,10 +875,10 @@
|
|||||||
<value>Import Advanced Rules</value>
|
<value>Import Advanced Rules</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvancedRemove" xml:space="preserve">
|
<data name="menuRoutingAdvancedRemove" xml:space="preserve">
|
||||||
<value>Remove selected</value>
|
<value>Remove selected (Delete)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
|
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
|
||||||
<value>Set as active rule</value>
|
<value>Set as active rule(Enter)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingBasic" xml:space="preserve">
|
<data name="menuRoutingBasic" xml:space="preserve">
|
||||||
<value>Basic Function</value>
|
<value>Basic Function</value>
|
||||||
@@ -926,13 +917,13 @@
|
|||||||
<value>Import Rules From File</value>
|
<value>Import Rules From File</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuImportRulesFromUrl" xml:space="preserve">
|
<data name="menuImportRulesFromUrl" xml:space="preserve">
|
||||||
<value>Import Rules From Sub Url</value>
|
<value>Import Rules From Subscription URL</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingRuleSetting" xml:space="preserve">
|
<data name="menuRoutingRuleSetting" xml:space="preserve">
|
||||||
<value>Rule Settings</value>
|
<value>Rule Settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRuleAdd" xml:space="preserve">
|
<data name="menuRuleAdd" xml:space="preserve">
|
||||||
<value>Rule Add</value>
|
<value>Add Rule</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRuleExportSelected" xml:space="preserve">
|
<data name="menuRuleExportSelected" xml:space="preserve">
|
||||||
<value>Export Selected Rules</value>
|
<value>Export Selected Rules</value>
|
||||||
@@ -941,19 +932,19 @@
|
|||||||
<value>Rule List</value>
|
<value>Rule List</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRuleRemove" xml:space="preserve">
|
<data name="menuRuleRemove" xml:space="preserve">
|
||||||
<value>Remove Rules</value>
|
<value>Remove Rule (Delete)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
|
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
|
||||||
<value>RoutingRuleDetailsSetting</value>
|
<value>RoutingRuleDetailsSetting</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoSort" xml:space="preserve">
|
<data name="TbAutoSort" xml:space="preserve">
|
||||||
<value>Domain and ip are auto sorted when saving</value>
|
<value>Domain, ip, process are auto sorted when saving</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRuleobjectDoc" xml:space="preserve">
|
<data name="TbRuleobjectDoc" xml:space="preserve">
|
||||||
<value>Ruleobject Doc</value>
|
<value>Ruleobject Doc</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDnsObjectDoc" xml:space="preserve">
|
<data name="TbDnsObjectDoc" xml:space="preserve">
|
||||||
<value>Support DnsObject</value>
|
<value>Support DnsObject, Click to view the document</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SubUrlTips" xml:space="preserve">
|
<data name="SubUrlTips" xml:space="preserve">
|
||||||
<value>Group please leave blank here</value>
|
<value>Group please leave blank here</value>
|
||||||
@@ -986,7 +977,7 @@
|
|||||||
<value>Display Log</value>
|
<value>Display Log</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuImportOldGuiConfig" xml:space="preserve">
|
<data name="menuImportOldGuiConfig" xml:space="preserve">
|
||||||
<value>Import old config guiNConfig</value>
|
<value>Import old config (guiNConfig)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbEnableTunAs" xml:space="preserve">
|
<data name="TbEnableTunAs" xml:space="preserve">
|
||||||
<value>Enable Tun</value>
|
<value>Enable Tun</value>
|
||||||
@@ -1043,16 +1034,16 @@
|
|||||||
<value>FontFamily(Require restart)</value>
|
<value>FontFamily(Require restart)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
||||||
<value>Copy the font TTF file to the directory guiFonts, restart the settings</value>
|
<value>Copy the font TTF/TTC file to the directory guiFonts, restart the settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||||
<value>http port=socks port+1</value>
|
<value>HTTP port=SOCKS port+1;Pac port=SOCKS port+4;API port=SOCKS port+5;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||||
<value>Set this with admin privileges, get admin privileges after startup</value>
|
<value>Set this with admin privileges, get admin privileges after startup</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsFontSize" xml:space="preserve">
|
<data name="TbSettingsFontSize" xml:space="preserve">
|
||||||
<value>FontSize</value>
|
<value>Font Size</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeProxyIP" xml:space="preserve">
|
<data name="TbSettingsTunModeProxyIP" xml:space="preserve">
|
||||||
<value>Proxy IP CIDR, separated by commas (,)</value>
|
<value>Proxy IP CIDR, separated by commas (,)</value>
|
||||||
@@ -1063,14 +1054,11 @@
|
|||||||
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
|
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
|
||||||
<value>Bypass Mode</value>
|
<value>Bypass Mode</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeBypassModeTip" xml:space="preserve">
|
|
||||||
<value>Enable: If no route matches, the final proxy</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
||||||
<value>SpeedTest Single Timeout Value</value>
|
<value>SpeedTest Single Timeout Value</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
||||||
<value>SpeedTest Url</value>
|
<value>SpeedTest URL</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeDNS" xml:space="preserve">
|
<data name="TbSettingsTunModeDNS" xml:space="preserve">
|
||||||
<value>DNS object, e.g. {"servers":[]}</value>
|
<value>DNS object, e.g. {"servers":[]}</value>
|
||||||
@@ -1091,7 +1079,7 @@
|
|||||||
<value>Enable hardware acceleration(Require restart)</value>
|
<value>Enable hardware acceleration(Require restart)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingWait" xml:space="preserve">
|
<data name="SpeedtestingWait" xml:space="preserve">
|
||||||
<value>Waiting for testing</value>
|
<value>Waiting for testing (press ESC to terminate)...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipDisplayLog" xml:space="preserve">
|
<data name="TipDisplayLog" xml:space="preserve">
|
||||||
<value>Please turn off when there is an abnormal disconnection</value>
|
<value>Please turn off when there is an abnormal disconnection</value>
|
||||||
@@ -1100,13 +1088,13 @@
|
|||||||
<value>Updates are not enabled, skip this subscription</value>
|
<value>Updates are not enabled, skip this subscription</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRebootAsAdmin" xml:space="preserve">
|
<data name="menuRebootAsAdmin" xml:space="preserve">
|
||||||
<value>Reboot as administrator</value>
|
<value>Restart as Administrator</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvMoreUrl" xml:space="preserve">
|
<data name="LvMoreUrl" xml:space="preserve">
|
||||||
<value>More urls, separated by commas;Subscription conversion will be invalid</value>
|
<value>More urls, separated by commas;Subscription conversion will be invalid</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedDisplayText" xml:space="preserve">
|
<data name="SpeedDisplayText" xml:space="preserve">
|
||||||
<value>{0}:{1}/s↑ | {2}/s↓</value>
|
<value>{0} : {1}/s↑ | {2}/s↓</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvAutoUpdateInterval" xml:space="preserve">
|
<data name="LvAutoUpdateInterval" xml:space="preserve">
|
||||||
<value>Automatic update interval(minutes)</value>
|
<value>Automatic update interval(minutes)</value>
|
||||||
@@ -1120,4 +1108,115 @@
|
|||||||
<data name="LvConvertTargetTip" xml:space="preserve">
|
<data name="LvConvertTargetTip" xml:space="preserve">
|
||||||
<value>Please leave blank if no conversion is required</value>
|
<value>Please leave blank if no conversion is required</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuDNSSetting" xml:space="preserve">
|
||||||
|
<value>DNS Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsCoreDnsSingbox" xml:space="preserve">
|
||||||
|
<value>sing-box DNS settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
|
||||||
|
<value>Please fill in DNS Structure, Click to view the document</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
|
||||||
|
<value>Click to import default DNS config</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbdomainStrategy4Singbox" xml:space="preserve">
|
||||||
|
<value>sing-box domain strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
|
||||||
|
<value>sing-box Mux Protocol</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRoutingRuleProcess" xml:space="preserve">
|
||||||
|
<value>Full process name (Tun mode)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRoutingRuleIP" xml:space="preserve">
|
||||||
|
<value>IP or IP CIDR</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRoutingRuleDomain" xml:space="preserve">
|
||||||
|
<value>Domain</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddHysteria2Server" xml:space="preserve">
|
||||||
|
<value>Add [Hysteria2] server</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
||||||
|
<value>Hysteria Max bandwidth (Up/Dw)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
|
||||||
|
<value>Use System Hosts</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddTuicServer" xml:space="preserve">
|
||||||
|
<value>Add [Tuic] server</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbHeaderType8" xml:space="preserve">
|
||||||
|
<value>Congestion control</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvPrevProfile" xml:space="preserve">
|
||||||
|
<value>Previous proxy remarks</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvNextProfile" xml:space="preserve">
|
||||||
|
<value>Next proxy remarks</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvPrevProfileTip" xml:space="preserve">
|
||||||
|
<value>Please make sure the remarks exists and is unique</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||||
|
<value>Enable additional Inbound</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
||||||
|
<value>Enable IPv6 Address</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddWireguardServer" xml:space="preserve">
|
||||||
|
<value>Add [Wireguard] server</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPrivateKey" xml:space="preserve">
|
||||||
|
<value>PrivateKey</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbReserved" xml:space="preserve">
|
||||||
|
<value>Reserved(2,3,4)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLocalAddress" xml:space="preserve">
|
||||||
|
<value>Address(Ip,Ipv6)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPath7" xml:space="preserve">
|
||||||
|
<value>obfs password</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="TbAutoScrollToEnd" xml:space="preserve">
|
||||||
|
<value>Auto ScrollToEnd</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
|
||||||
|
<value>Speed Ping Test URL</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
|
||||||
|
<value>Updating subscription, only determine remarks exists</value>
|
||||||
|
</data>
|
||||||
|
<data name="SpeedtestingStop" xml:space="preserve">
|
||||||
|
<value>Test terminating...</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportRequestHostTip5" xml:space="preserve">
|
||||||
|
<value>*grpc Authority</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddHttpServer" xml:space="preserve">
|
||||||
|
<value>Add [Http] server</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||||
|
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||||
|
<value>Enable fragment</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
||||||
|
<value>Enable cache file for sing-box (ruleset files)</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
|
||||||
|
<value>Custom the rule-set of sing-box</value>
|
||||||
|
</data>
|
||||||
|
<data name="NeedRebootTips" xml:space="preserve">
|
||||||
|
<value>Successful operation. Click the settings menu to reboot the app.</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuOpenTheFileLocation" xml:space="preserve">
|
||||||
|
<value>Open the storage location</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -187,10 +187,10 @@
|
|||||||
<value>Исходная конфигурация</value>
|
<value>Исходная конфигурация</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestCore" xml:space="preserve">
|
<data name="IsLatestCore" xml:space="preserve">
|
||||||
<value>{0} является последней версией.</value>
|
<value>{0} {1} является последней версией.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestN" xml:space="preserve">
|
<data name="IsLatestN" xml:space="preserve">
|
||||||
<value>{0} является последней версией.</value>
|
<value>{0} {1} является последней версией.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvAddress" xml:space="preserve">
|
<data name="LvAddress" xml:space="preserve">
|
||||||
<value>Адрес</value>
|
<value>Адрес</value>
|
||||||
@@ -300,9 +300,6 @@
|
|||||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||||
<value>Файл конфигурации клиента сохранен по адресу: {0}</value>
|
<value>Файл конфигурации клиента сохранен по адресу: {0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SaveServerConfigurationIn" xml:space="preserve">
|
|
||||||
<value>Файл конфигурации сервера сохранен по адресу: {0}</value>
|
|
||||||
</data>
|
|
||||||
<data name="StartService" xml:space="preserve">
|
<data name="StartService" xml:space="preserve">
|
||||||
<value>Запуск сервиса ({0})...</value>
|
<value>Запуск сервиса ({0})...</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -320,7 +317,7 @@
|
|||||||
<value>Сканирование URL-адреса импорта успешна.</value>
|
<value>Сканирование URL-адреса импорта успешна.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TestMeOutput" xml:space="preserve">
|
<data name="TestMeOutput" xml:space="preserve">
|
||||||
<value>Пинг текущей службы: {0} мс</value>
|
<value>Задержка текущего сервера: {0} мс</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="OperationSuccess" xml:space="preserve">
|
<data name="OperationSuccess" xml:space="preserve">
|
||||||
<value>Операция успешна</value>
|
<value>Операция успешна</value>
|
||||||
@@ -338,7 +335,7 @@
|
|||||||
<value>Примечания</value>
|
<value>Примечания</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvUrl" xml:space="preserve">
|
<data name="LvUrl" xml:space="preserve">
|
||||||
<value>Url(Необязательно)</value>
|
<value>URL (необязательно)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvCount" xml:space="preserve">
|
<data name="LvCount" xml:space="preserve">
|
||||||
<value>Количество</value>
|
<value>Количество</value>
|
||||||
@@ -508,6 +505,9 @@
|
|||||||
<data name="TbSettingsColorMode" xml:space="preserve">
|
<data name="TbSettingsColorMode" xml:space="preserve">
|
||||||
<value>Тёмный режим</value>
|
<value>Тёмный режим</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
|
||||||
|
<value>Следить за системной темой</value>
|
||||||
|
</data>
|
||||||
<data name="TbSettingsLanguage" xml:space="preserve">
|
<data name="TbSettingsLanguage" xml:space="preserve">
|
||||||
<value>Язык (требуется перезапуск)</value>
|
<value>Язык (требуется перезапуск)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -532,20 +532,17 @@
|
|||||||
<data name="menuClearServerStatistics" xml:space="preserve">
|
<data name="menuClearServerStatistics" xml:space="preserve">
|
||||||
<value>Очистить всю статистику</value>
|
<value>Очистить всю статистику</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuPingServer" xml:space="preserve">
|
|
||||||
<value>Проверить пинг серверов (Ctrl+P)</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRealPingServer" xml:space="preserve">
|
<data name="menuRealPingServer" xml:space="preserve">
|
||||||
<value>Тест на реальную задержку серверов (Ctrl+R)</value>
|
<value>Тест на реальную задержку сервера (Ctrl+R)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSortServerResult" xml:space="preserve">
|
<data name="menuSortServerResult" xml:space="preserve">
|
||||||
<value>Сортировать по результату теста</value>
|
<value>Сортировать по результату теста</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSpeedServer" xml:space="preserve">
|
<data name="menuSpeedServer" xml:space="preserve">
|
||||||
<value>Проверить скорость загрузки серверов (Ctrl+T)</value>
|
<value>Тест на скорость загрузки сервера (Ctrl+T)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTcpingServer" xml:space="preserve">
|
<data name="menuTcpingServer" xml:space="preserve">
|
||||||
<value>Тестировать сервера с tcping (Ctrl+O)</value>
|
<value>Тест задержки с tcping (Ctrl+O)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTestMe" xml:space="preserve">
|
<data name="menuTestMe" xml:space="preserve">
|
||||||
<value>Проверить текущий статус службы</value>
|
<value>Проверить текущий статус службы</value>
|
||||||
@@ -553,9 +550,6 @@
|
|||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>Экспортировать выбранный сервер для клиента</value>
|
<value>Экспортировать выбранный сервер для клиента</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ServerConfig" xml:space="preserve">
|
|
||||||
<value>Экспортировать выбранный сервер для сервера</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>Экспорт URL-адресов общего доступа в буфер обмена (Ctrl+C)</value>
|
<value>Экспорт URL-адресов общего доступа в буфер обмена (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -647,7 +641,7 @@
|
|||||||
<value>Тип камуфляжа</value>
|
<value>Тип камуфляжа</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbId" xml:space="preserve">
|
<data name="TbId" xml:space="preserve">
|
||||||
<value>UUID(id)</value>
|
<value>UUID (id)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbNetwork" xml:space="preserve">
|
<data name="TbNetwork" xml:space="preserve">
|
||||||
<value>Транспортный протокол сети</value>
|
<value>Транспортный протокол сети</value>
|
||||||
@@ -659,7 +653,7 @@
|
|||||||
<value>Порт</value>
|
<value>Порт</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRemarks" xml:space="preserve">
|
<data name="TbRemarks" xml:space="preserve">
|
||||||
<value>Псевдоним (примечания)</value>
|
<value>Примечание</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRequestHost" xml:space="preserve">
|
<data name="TbRequestHost" xml:space="preserve">
|
||||||
<value>Маскирующий домен (хост)</value>
|
<value>Маскирующий домен (хост)</value>
|
||||||
@@ -707,7 +701,7 @@
|
|||||||
<value>txtPreSocksPort</value>
|
<value>txtPreSocksPort</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipPreSocksPort" xml:space="preserve">
|
<data name="TipPreSocksPort" xml:space="preserve">
|
||||||
<value>* После установки этого значения служба socks будет запущена с использованием V2ray для обеспечения таких функций, как отображение скорости</value>
|
<value>* После установки этого значения служба socks будет запущена с использованием Xray/sing-box(Tun) для обеспечения таких функций, как отображение скорости</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbBrowse" xml:space="preserve">
|
<data name="TbBrowse" xml:space="preserve">
|
||||||
<value>Просмотр</value>
|
<value>Просмотр</value>
|
||||||
@@ -722,16 +716,22 @@
|
|||||||
<value>Разрешить подключения из локальной сети</value>
|
<value>Разрешить подключения из локальной сети</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsAutoHideStartup" xml:space="preserve">
|
<data name="TbSettingsAutoHideStartup" xml:space="preserve">
|
||||||
<value>Auto hide startup</value>
|
<value>Автоскрытие при автозапуске</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
|
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
|
||||||
<value>Интервал автоматического обновления Geo в часах</value>
|
<value>Интервал автоматического обновления Geo в часах</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="LvAutoUpdateInterval" xml:space="preserve">
|
||||||
|
<value>Интервал автоматического обновления в минутах</value>
|
||||||
|
</data>
|
||||||
<data name="TbSettingsCore" xml:space="preserve">
|
<data name="TbSettingsCore" xml:space="preserve">
|
||||||
<value>Ядро: базовые настройки</value>
|
<value>Ядро: базовые настройки</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCoreDns" xml:space="preserve">
|
<data name="TbSettingsCoreDns" xml:space="preserve">
|
||||||
<value>Ядро: настройки DNS</value>
|
<value>Настройки DNS V2ray</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsCoreDnsSingbox" xml:space="preserve">
|
||||||
|
<value>Настройки DNS sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
||||||
<value>Ядро: настройки KCP</value>
|
<value>Ядро: настройки KCP</value>
|
||||||
@@ -799,9 +799,6 @@
|
|||||||
<data name="TbSettingsStatistics" xml:space="preserve">
|
<data name="TbSettingsStatistics" xml:space="preserve">
|
||||||
<value>Включить статистику (требуется перезагрузка)</value>
|
<value>Включить статистику (требуется перезагрузка)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStatisticsFreshRate" xml:space="preserve">
|
|
||||||
<value>Частота обновления статистики в секундах</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsSubConvert" xml:space="preserve">
|
<data name="TbSettingsSubConvert" xml:space="preserve">
|
||||||
<value>URL-адрес конверсии подписки</value>
|
<value>URL-адрес конверсии подписки</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -812,7 +809,7 @@
|
|||||||
<value>Включить протокол безопасности TLS v1.3 (обновление подписки)</value>
|
<value>Включить протокол безопасности TLS v1.3 (обновление подписки)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
|
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
|
||||||
<value>Tray right-click menu servers display limit</value>
|
<value>Лимит серверов в меню трея</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsUdpEnabled" xml:space="preserve">
|
<data name="TbSettingsUdpEnabled" xml:space="preserve">
|
||||||
<value>Включить UDP</value>
|
<value>Включить UDP</value>
|
||||||
@@ -941,7 +938,7 @@
|
|||||||
<value>Список правил</value>
|
<value>Список правил</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRuleRemove" xml:space="preserve">
|
<data name="menuRuleRemove" xml:space="preserve">
|
||||||
<value>Удалить правила</value>
|
<value>Удалить правила (Delete)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
|
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
|
||||||
<value>RoutingRuleDetailsSetting</value>
|
<value>RoutingRuleDetailsSetting</value>
|
||||||
@@ -956,7 +953,7 @@
|
|||||||
<value>Поддержка DnsObject</value>
|
<value>Поддержка DnsObject</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SubUrlTips" xml:space="preserve">
|
<data name="SubUrlTips" xml:space="preserve">
|
||||||
<value>Group please leave blank here</value>
|
<value>Необязательное поле</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipChangeRouting" xml:space="preserve">
|
<data name="TipChangeRouting" xml:space="preserve">
|
||||||
<value>Настройки маршрутизации изменены</value>
|
<value>Настройки маршрутизации изменены</value>
|
||||||
@@ -968,7 +965,7 @@
|
|||||||
<value>Только маршрут</value>
|
<value>Только маршрут</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMixedTestServer" xml:space="preserve">
|
<data name="menuMixedTestServer" xml:space="preserve">
|
||||||
<value>Тест задержки и скорости (Ctrl+E)</value>
|
<value>Тест задержки и скорости всех серверов (Ctrl+E)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvTestDelay" xml:space="preserve">
|
<data name="LvTestDelay" xml:space="preserve">
|
||||||
<value>Задержка (ms)</value>
|
<value>Задержка (ms)</value>
|
||||||
@@ -989,7 +986,7 @@
|
|||||||
<value>Импортировать старый конфиг guiNConfig</value>
|
<value>Импортировать старый конфиг guiNConfig</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbEnableTunAs" xml:space="preserve">
|
<data name="TbEnableTunAs" xml:space="preserve">
|
||||||
<value>Включить интерфейс</value>
|
<value>Режим VPN</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsNewPort4LAN" xml:space="preserve">
|
<data name="TbSettingsNewPort4LAN" xml:space="preserve">
|
||||||
<value>Новый порт для локальной сети</value>
|
<value>Новый порт для локальной сети</value>
|
||||||
@@ -1043,7 +1040,7 @@
|
|||||||
<value>Шрифт (требуется перезагрузка)</value>
|
<value>Шрифт (требуется перезагрузка)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
||||||
<value>Скопируйте файл шрифта TTF в каталог guiFonts, перезапустите настройки</value>
|
<value>Скопируйте файл шрифта TTF/TTC в каталог guiFonts, перезапустите настройки</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||||
<value>HTTP port=socks port+1</value>
|
<value>HTTP port=socks port+1</value>
|
||||||
@@ -1057,4 +1054,19 @@
|
|||||||
<data name="TbSettingsEnableHWA" xml:space="preserve">
|
<data name="TbSettingsEnableHWA" xml:space="preserve">
|
||||||
<value>Включить аппаратное ускорение (требуется перезагрузка)</value>
|
<value>Включить аппаратное ускорение (требуется перезагрузка)</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuRebootAsAdmin" xml:space="preserve">
|
||||||
|
<value>Перезагрузить как администратор</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuDNSSetting" xml:space="preserve">
|
||||||
|
<value>Настройки DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
|
||||||
|
<value>Включить логгирование в файл</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
||||||
|
<value>Таймаут одиночного спидтеста</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
||||||
|
<value>URL спидтеста</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -187,10 +187,10 @@
|
|||||||
<value>初始化配置</value>
|
<value>初始化配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestCore" xml:space="preserve">
|
<data name="IsLatestCore" xml:space="preserve">
|
||||||
<value>{0} 已是最新版本。</value>
|
<value>{0} {1} 已是最新版本。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestN" xml:space="preserve">
|
<data name="IsLatestN" xml:space="preserve">
|
||||||
<value>{0} 已是最新版本。</value>
|
<value>{0} {1} 已是最新版本。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvAddress" xml:space="preserve">
|
<data name="LvAddress" xml:space="preserve">
|
||||||
<value>地址</value>
|
<value>地址</value>
|
||||||
@@ -300,9 +300,6 @@
|
|||||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||||
<value>客户端配置文件保存在:{0}</value>
|
<value>客户端配置文件保存在:{0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SaveServerConfigurationIn" xml:space="preserve">
|
|
||||||
<value>服务端配置文件保存在:{0}</value>
|
|
||||||
</data>
|
|
||||||
<data name="StartService" xml:space="preserve">
|
<data name="StartService" xml:space="preserve">
|
||||||
<value>启动服务({0})...</value>
|
<value>启动服务({0})...</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -362,7 +359,7 @@
|
|||||||
<value>请填写正确的自定义DNS</value>
|
<value>请填写正确的自定义DNS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip1" xml:space="preserve">
|
<data name="TransportPathTip1" xml:space="preserve">
|
||||||
<value>*ws path</value>
|
<value>*ws/httpupgrade path</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip2" xml:space="preserve">
|
<data name="TransportPathTip2" xml:space="preserve">
|
||||||
<value>*h2 path</value>
|
<value>*h2 path</value>
|
||||||
@@ -377,7 +374,7 @@
|
|||||||
<value>*http host中间逗号(,)分隔</value>
|
<value>*http host中间逗号(,)分隔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip2" xml:space="preserve">
|
<data name="TransportRequestHostTip2" xml:space="preserve">
|
||||||
<value>*ws host</value>
|
<value>*ws/httpupgrade host</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip3" xml:space="preserve">
|
<data name="TransportRequestHostTip3" xml:space="preserve">
|
||||||
<value>*h2 host中间逗号(,)分隔</value>
|
<value>*h2 host中间逗号(,)分隔</value>
|
||||||
@@ -508,6 +505,9 @@
|
|||||||
<data name="TbSettingsColorMode" xml:space="preserve">
|
<data name="TbSettingsColorMode" xml:space="preserve">
|
||||||
<value>暗黑模式</value>
|
<value>暗黑模式</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
|
||||||
|
<value>是否跟随系统主题</value>
|
||||||
|
</data>
|
||||||
<data name="TbSettingsLanguage" xml:space="preserve">
|
<data name="TbSettingsLanguage" xml:space="preserve">
|
||||||
<value>语言(重启)</value>
|
<value>语言(重启)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -532,9 +532,6 @@
|
|||||||
<data name="menuClearServerStatistics" xml:space="preserve">
|
<data name="menuClearServerStatistics" xml:space="preserve">
|
||||||
<value>清除所有服务统计数据</value>
|
<value>清除所有服务统计数据</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuPingServer" xml:space="preserve">
|
|
||||||
<value>测试服务器延迟Ping(多选) (Ctrl+P)</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuRealPingServer" xml:space="preserve">
|
<data name="menuRealPingServer" xml:space="preserve">
|
||||||
<value>测试服务器真连接延迟(多选) (Ctrl+R)</value>
|
<value>测试服务器真连接延迟(多选) (Ctrl+R)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -553,9 +550,6 @@
|
|||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>导出所选服务器为客户端配置</value>
|
<value>导出所选服务器为客户端配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ServerConfig" xml:space="preserve">
|
|
||||||
<value>导出所选服务器为服务端配置</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>批量导出分享URL至剪贴板(多选) (Ctrl+C)</value>
|
<value>批量导出分享URL至剪贴板(多选) (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -707,7 +701,7 @@
|
|||||||
<value>Socks端口</value>
|
<value>Socks端口</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipPreSocksPort" xml:space="preserve">
|
<data name="TipPreSocksPort" xml:space="preserve">
|
||||||
<value>* 自定义配置的Socks端口值,可不设置;当设置此值后,将使用V2ray-core额外启动一个前置Socks服务,提供分流和速度显示等功能</value>
|
<value>* 自定义配置的Socks端口值,可不设置;当设置此值后,将使用Xray/sing-box(Tun)额外启动一个前置Socks服务,提供分流和速度显示等功能</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbBrowse" xml:space="preserve">
|
<data name="TbBrowse" xml:space="preserve">
|
||||||
<value>浏览</value>
|
<value>浏览</value>
|
||||||
@@ -731,7 +725,7 @@
|
|||||||
<value>Core: 基础设置</value>
|
<value>Core: 基础设置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCoreDns" xml:space="preserve">
|
<data name="TbSettingsCoreDns" xml:space="preserve">
|
||||||
<value>Core: DNS设置</value>
|
<value>V2ray DNS设置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
<data name="TbSettingsCoreKcp" xml:space="preserve">
|
||||||
<value>Core: KCP设置</value>
|
<value>Core: KCP设置</value>
|
||||||
@@ -799,9 +793,6 @@
|
|||||||
<data name="TbSettingsStatistics" xml:space="preserve">
|
<data name="TbSettingsStatistics" xml:space="preserve">
|
||||||
<value>启用统计(实时网速显示,需重启)</value>
|
<value>启用统计(实时网速显示,需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStatisticsFreshRate" xml:space="preserve">
|
|
||||||
<value>统计刷新频率(单位秒)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsSubConvert" xml:space="preserve">
|
<data name="TbSettingsSubConvert" xml:space="preserve">
|
||||||
<value>订阅转换网址(可选)</value>
|
<value>订阅转换网址(可选)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -884,10 +875,10 @@
|
|||||||
<value>一键导入高级规则</value>
|
<value>一键导入高级规则</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvancedRemove" xml:space="preserve">
|
<data name="menuRoutingAdvancedRemove" xml:space="preserve">
|
||||||
<value>移除所选规则</value>
|
<value>移除所选规则 (Delete)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
|
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
|
||||||
<value>设为活动规则</value>
|
<value>设为活动规则 (Enter)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingBasic" xml:space="preserve">
|
<data name="menuRoutingBasic" xml:space="preserve">
|
||||||
<value>基础功能</value>
|
<value>基础功能</value>
|
||||||
@@ -902,7 +893,7 @@
|
|||||||
<value>域名解析策略</value>
|
<value>域名解析策略</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbenableRoutingAdvanced" xml:space="preserve">
|
<data name="TbenableRoutingAdvanced" xml:space="preserve">
|
||||||
<value>启用路由高级功能</value>
|
<value>启用高级功能</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRoutingTabBlock" xml:space="preserve">
|
<data name="TbRoutingTabBlock" xml:space="preserve">
|
||||||
<value>3.阻止的Domain或IP</value>
|
<value>3.阻止的Domain或IP</value>
|
||||||
@@ -941,19 +932,19 @@
|
|||||||
<value>规则列表</value>
|
<value>规则列表</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRuleRemove" xml:space="preserve">
|
<data name="menuRuleRemove" xml:space="preserve">
|
||||||
<value>移除所选规则</value>
|
<value>移除所选规则 (Delete)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
|
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
|
||||||
<value>路由规则详情设置</value>
|
<value>路由规则详情设置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoSort" xml:space="preserve">
|
<data name="TbAutoSort" xml:space="preserve">
|
||||||
<value>保存时Domain和IP自动排序</value>
|
<value>保存时Domain, IP, 进程名 自动排序</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRuleobjectDoc" xml:space="preserve">
|
<data name="TbRuleobjectDoc" xml:space="preserve">
|
||||||
<value>规则详细说明文档</value>
|
<value>规则详细说明文档</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbDnsObjectDoc" xml:space="preserve">
|
<data name="TbDnsObjectDoc" xml:space="preserve">
|
||||||
<value>支持填写DnsObject,JSON格式</value>
|
<value>支持填写DnsObject,JSON格式,点击查看文档</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SubUrlTips" xml:space="preserve">
|
<data name="SubUrlTips" xml:space="preserve">
|
||||||
<value>普通分组此处请留空</value>
|
<value>普通分组此处请留空</value>
|
||||||
@@ -1043,10 +1034,10 @@
|
|||||||
<value>当前字体(需重启)</value>
|
<value>当前字体(需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
||||||
<value>拷贝字体TTF文件到目录guiFonts,重启设置</value>
|
<value>拷贝字体TTF/TTC文件到目录guiFonts,重启设置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
||||||
<value>http端口=socks端口+1</value>
|
<value>http端口=socks端口+1;Pac端口=socks端口+4;API端口=socks端口+5;</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||||
<value>以管理员权限设置此项,在启动后获得管理员权限</value>
|
<value>以管理员权限设置此项,在启动后获得管理员权限</value>
|
||||||
@@ -1063,9 +1054,6 @@
|
|||||||
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
|
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
|
||||||
<value>绕行模式</value>
|
<value>绕行模式</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeBypassModeTip" xml:space="preserve">
|
|
||||||
<value>启用:路由无匹配则最终代理</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
|
||||||
<value>测速单个超时值</value>
|
<value>测速单个超时值</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1091,7 +1079,7 @@
|
|||||||
<value>启用硬件加速(需重启)</value>
|
<value>启用硬件加速(需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingWait" xml:space="preserve">
|
<data name="SpeedtestingWait" xml:space="preserve">
|
||||||
<value>等待测试中...</value>
|
<value>等待测试中(按ESC终止)...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipDisplayLog" xml:space="preserve">
|
<data name="TipDisplayLog" xml:space="preserve">
|
||||||
<value>当有异常断流时请关闭</value>
|
<value>当有异常断流时请关闭</value>
|
||||||
@@ -1117,4 +1105,115 @@
|
|||||||
<data name="LvConvertTargetTip" xml:space="preserve">
|
<data name="LvConvertTargetTip" xml:space="preserve">
|
||||||
<value>不需要转换时请留空</value>
|
<value>不需要转换时请留空</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuDNSSetting" xml:space="preserve">
|
||||||
|
<value>DNS设置</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsCoreDnsSingbox" xml:space="preserve">
|
||||||
|
<value>sing-box DNS设置</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
|
||||||
|
<value>请填写 DNS JSON 结构,点击查看文档</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
|
||||||
|
<value>点击导入默认DNS配置</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbdomainStrategy4Singbox" xml:space="preserve">
|
||||||
|
<value>sing-box域名解析策略</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
|
||||||
|
<value>sing-box Mux 多路复用协议</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRoutingRuleProcess" xml:space="preserve">
|
||||||
|
<value>进程名全称 (Tun模式)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRoutingRuleDomain" xml:space="preserve">
|
||||||
|
<value>Domain</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRoutingRuleIP" xml:space="preserve">
|
||||||
|
<value>IP 或 IP CIDR</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddHysteria2Server" xml:space="preserve">
|
||||||
|
<value>添加[Hysteria2]服务器</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
||||||
|
<value>Hysteria 最大带宽(Up/Dw)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
|
||||||
|
<value>使用系统hosts</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddTuicServer" xml:space="preserve">
|
||||||
|
<value>添加[Tuic]服务器</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbHeaderType8" xml:space="preserve">
|
||||||
|
<value>拥塞控制算法</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvPrevProfile" xml:space="preserve">
|
||||||
|
<value>前置代理别名</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvNextProfile" xml:space="preserve">
|
||||||
|
<value>落地代理別名</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvPrevProfileTip" xml:space="preserve">
|
||||||
|
<value>请确保别名存在并唯一</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||||
|
<value>启用额外监听端口</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
||||||
|
<value>启用IPv6</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddWireguardServer" xml:space="preserve">
|
||||||
|
<value>添加[Wireguard]服务器</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPrivateKey" xml:space="preserve">
|
||||||
|
<value>PrivateKey</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbReserved" xml:space="preserve">
|
||||||
|
<value>Reserved(2,3,4)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbLocalAddress" xml:space="preserve">
|
||||||
|
<value>Address(Ip,Ipv6)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPath7" xml:space="preserve">
|
||||||
|
<value>混淆密码(obfs password)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbRuleMatchingTips" xml:space="preserve">
|
||||||
|
<value>(Domain 或 IP 或 进程名) 与 Port 与 Protocol 与 InboundTag => OutboundTag</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbAutoScrollToEnd" xml:space="preserve">
|
||||||
|
<value>自动滚动到末尾</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
|
||||||
|
<value>真连接测试地址</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
|
||||||
|
<value>更新订阅时只判断别名已存在否</value>
|
||||||
|
</data>
|
||||||
|
<data name="SpeedtestingStop" xml:space="preserve">
|
||||||
|
<value>测试终止中...</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportRequestHostTip5" xml:space="preserve">
|
||||||
|
<value>*grpc Authority</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuAddHttpServer" xml:space="preserve">
|
||||||
|
<value>添加[Http]服务器</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||||
|
<value>启用分片(Fragment)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||||
|
<value>使用Xray且非Tun模式启用,和分组前置代理冲突</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
|
||||||
|
<value>启用sing-box(规则集文件)的缓存文件</value>
|
||||||
|
</data>
|
||||||
|
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
|
||||||
|
<value>自定义sing-box rule-set</value>
|
||||||
|
</data>
|
||||||
|
<data name="NeedRebootTips" xml:space="preserve">
|
||||||
|
<value>操作成功。请点击设置菜单重启应用。</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuOpenTheFileLocation" xml:space="preserve">
|
||||||
|
<value>打开存储所在的位置</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -4,56 +4,7 @@
|
|||||||
"error": "Verror.log",
|
"error": "Verror.log",
|
||||||
"loglevel": "warning"
|
"loglevel": "warning"
|
||||||
},
|
},
|
||||||
"inbounds": [{
|
"inbounds": [],
|
||||||
"tag": "tag1",
|
|
||||||
"port": 10808,
|
|
||||||
"protocol": "socks",
|
|
||||||
"listen": "127.0.0.1",
|
|
||||||
"settings": {
|
|
||||||
"auth": "noauth",
|
|
||||||
"udp": true
|
|
||||||
},
|
|
||||||
"sniffing": {
|
|
||||||
"enabled": true,
|
|
||||||
"destOverride": [
|
|
||||||
"http",
|
|
||||||
"tls"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "tag2",
|
|
||||||
"port": 10809,
|
|
||||||
"protocol": "http",
|
|
||||||
"listen": "127.0.0.1",
|
|
||||||
"settings": {
|
|
||||||
"allowTransparent": false
|
|
||||||
},
|
|
||||||
"sniffing": {
|
|
||||||
"enabled": true,
|
|
||||||
"destOverride": [
|
|
||||||
"http",
|
|
||||||
"tls"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "tag3",
|
|
||||||
"port": 10809,
|
|
||||||
"protocol": "http",
|
|
||||||
"listen": "127.0.0.1",
|
|
||||||
"settings": {
|
|
||||||
"allowTransparent": false
|
|
||||||
},
|
|
||||||
"sniffing": {
|
|
||||||
"enabled": true,
|
|
||||||
"destOverride": [
|
|
||||||
"http",
|
|
||||||
"tls"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outbounds": [{
|
"outbounds": [{
|
||||||
"tag": "proxy",
|
"tag": "proxy",
|
||||||
"protocol": "vmess",
|
"protocol": "vmess",
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"tag": "proxy",
|
||||||
|
"protocol": "vmess",
|
||||||
|
"settings": {
|
||||||
|
"vnext": [
|
||||||
|
{
|
||||||
|
"address": "v2ray.cool",
|
||||||
|
"port": 10086,
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"id": "a3482e88-686a-4a58-8126-99c9df64b7bf",
|
||||||
|
"security": "auto"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"address": "v2ray.cool",
|
||||||
|
"method": "chacha20",
|
||||||
|
"ota": false,
|
||||||
|
"password": "123456",
|
||||||
|
"port": 10086,
|
||||||
|
"level": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"streamSettings": {
|
||||||
|
"network": "tcp"
|
||||||
|
},
|
||||||
|
"mux": {
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"log": {
|
|
||||||
"access": "/var/log/v2ray/access.log",
|
|
||||||
"error": "/var/log/v2ray/error.log",
|
|
||||||
"loglevel": "warning"
|
|
||||||
},
|
|
||||||
"inbounds": [{
|
|
||||||
"port": 10086,
|
|
||||||
"protocol": "vmess",
|
|
||||||
"settings": {
|
|
||||||
"clients": [{
|
|
||||||
"id": "23ad6b10-8d1a-40f7-8ad0-e3e35cd38297",
|
|
||||||
"level": 1,
|
|
||||||
"email": "t@t.tt"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"streamSettings": {
|
|
||||||
"network": "tcp"
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"outbounds": [{
|
|
||||||
"protocol": "freedom",
|
|
||||||
"settings": {}
|
|
||||||
}, {
|
|
||||||
"protocol": "blackhole",
|
|
||||||
"settings": {},
|
|
||||||
"tag": "block"
|
|
||||||
}],
|
|
||||||
"routing": {
|
|
||||||
"domainStrategy": "IPIfNonMatch",
|
|
||||||
"rules": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"log": {
|
||||||
|
"level": "debug",
|
||||||
|
"timestamp": true
|
||||||
|
},
|
||||||
|
"inbounds": [],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"type": "vless",
|
||||||
|
"tag": "proxy",
|
||||||
|
"server": "",
|
||||||
|
"server_port": 443
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "direct",
|
||||||
|
"tag": "direct"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "block",
|
||||||
|
"tag": "block"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "dns_out",
|
||||||
|
"type": "dns"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"route": {
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"protocol": [ "dns" ],
|
||||||
|
"outbound": "dns_out"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"type": "vless",
|
||||||
|
"tag": "proxy",
|
||||||
|
"server": "",
|
||||||
|
"server_port": 443
|
||||||
|
}
|
||||||
@@ -13,20 +13,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"outboundTag": "proxy",
|
"outboundTag": "proxy",
|
||||||
"ip": [
|
|
||||||
"geoip:cloudflare",
|
|
||||||
"geoip:cloudfront",
|
|
||||||
"geoip:facebook",
|
|
||||||
"geoip:fastly",
|
|
||||||
"geoip:google",
|
|
||||||
"geoip:netflix",
|
|
||||||
"geoip:telegram",
|
|
||||||
"geoip:twitter"
|
|
||||||
],
|
|
||||||
"domain": [
|
"domain": [
|
||||||
"geosite:gfw",
|
"geosite:geolocation-!cn",
|
||||||
"geosite:greatfire",
|
"geosite:greatfire"
|
||||||
"geosite:tld-!cn"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
{
|
{
|
||||||
"outboundTag": "direct",
|
"outboundTag": "direct",
|
||||||
"domain": [
|
"domain": [
|
||||||
"geosite:cn"
|
"geosite:cn",
|
||||||
|
"geosite:geolocation-cn"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"tag": "remote",
|
||||||
|
"address": "tcp://8.8.8.8",
|
||||||
|
"strategy": "ipv4_only",
|
||||||
|
"detour": "proxy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "local",
|
||||||
|
"address": "223.5.5.5",
|
||||||
|
"strategy": "ipv4_only",
|
||||||
|
"detour": "direct"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "block",
|
||||||
|
"address": "rcode://success"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"rule_set": [
|
||||||
|
"geosite-geolocation-!cn"
|
||||||
|
],
|
||||||
|
"server": "remote"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule_set": [
|
||||||
|
"geosite-category-ads-all"
|
||||||
|
],
|
||||||
|
"server": "block"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"final": "local"
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user