Compare commits
306 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c22b57927c | ||
|
|
81b84d235c | ||
|
|
488e8aab00 | ||
|
|
fc43a9a726 | ||
|
|
31947fdcb3 | ||
|
|
34c7963d28 | ||
|
|
d91b0afb9a | ||
|
|
82eb3fd6bd | ||
|
|
3d3d3f83df | ||
|
|
6879c75bc8 | ||
|
|
b02ad6cdab | ||
|
|
f7b16952ea | ||
|
|
f0d05a7d4e | ||
|
|
d6ca317b20 | ||
|
|
2879fddfd9 | ||
|
|
b6c09470fc | ||
|
|
9fdf6c6c32 | ||
|
|
79085af994 | ||
|
|
d189f4b443 | ||
|
|
c9d65e5cd9 | ||
|
|
639d62588a | ||
|
|
6c9db51fd5 | ||
|
|
f0dbb6b22c | ||
|
|
f10f7b6268 | ||
|
|
48a5cbc552 | ||
|
|
6721d150e0 | ||
|
|
54c16cad7d | ||
|
|
ae3ab15245 | ||
|
|
d3c0f50fec | ||
|
|
43753b1b7a | ||
|
|
6f3e4b3682 | ||
|
|
b57cdd31bd | ||
|
|
b936c194e4 | ||
|
|
064431421a | ||
|
|
9d49c7aad0 | ||
|
|
a6f27e5071 | ||
|
|
8d1d10b783 | ||
|
|
61bea05f63 | ||
|
|
bbe7c7b884 | ||
|
|
a432852b78 | ||
|
|
770e8b8cfa | ||
|
|
7faabdc375 | ||
|
|
a9860418ba | ||
|
|
30ff9d0ea9 | ||
|
|
bbc2298939 | ||
|
|
3286e8e24d | ||
|
|
372f3991e1 | ||
|
|
9aa5c0d135 | ||
|
|
9e9808e489 | ||
|
|
3dd75b17cf | ||
|
|
2504b4737b | ||
|
|
8ff04dca0d | ||
|
|
d893ee4829 | ||
|
|
dfc5ec0705 | ||
|
|
8023eb74c9 | ||
|
|
bb4d3997ad | ||
|
|
7ede3af762 | ||
|
|
97ea1c7a9e | ||
|
|
43bb2c0fb8 | ||
|
|
6e7196bb27 | ||
|
|
87a71d58e8 | ||
|
|
32ffd43fe3 | ||
|
|
6500c8d85e | ||
|
|
9866d436da | ||
|
|
0f4884d9d8 | ||
|
|
5a81441351 | ||
|
|
e8721bfb6b | ||
|
|
1b09d95209 | ||
|
|
35f3b5a50e | ||
|
|
ff5203a561 | ||
|
|
c3c1ced309 | ||
|
|
08b1c8ec83 | ||
|
|
1dd3ee4e0a | ||
|
|
06d0c6517d | ||
|
|
4938ce6364 | ||
|
|
25f3fc354f | ||
|
|
ad1a1f8015 | ||
|
|
5c070e2ca8 | ||
|
|
70ea21fca2 | ||
|
|
bc3593871b | ||
|
|
355a424be2 | ||
|
|
0ffa9a0cc8 | ||
|
|
72fecb2b9a | ||
|
|
4e9dfe5478 | ||
|
|
c79e2e3ad4 | ||
|
|
7c33c1c322 | ||
|
|
ea32f75925 | ||
|
|
7eaed21b9a | ||
|
|
cfe8fcd28d | ||
|
|
9f4718af70 | ||
|
|
39faccfd0b | ||
|
|
7545763dae | ||
|
|
c2928be35d | ||
|
|
449bb40d48 | ||
|
|
4caf1a1e63 | ||
|
|
01b205e6f1 | ||
|
|
160d3843a6 | ||
|
|
5efb784115 | ||
|
|
acde5b8384 | ||
|
|
373ee6586a | ||
|
|
215308c329 | ||
|
|
478cadba5e | ||
|
|
f4af4da791 | ||
|
|
22d4f435de | ||
|
|
ccb8cd5c04 | ||
|
|
e963f9e349 | ||
|
|
e3c2a4b8da | ||
|
|
324f46cdad | ||
|
|
691b19b5fd | ||
|
|
63ed2311dc | ||
|
|
d59e59ca40 | ||
|
|
c9a278b4a2 | ||
|
|
8ee5304148 | ||
|
|
3beaa8145f | ||
|
|
e30c55a0af | ||
|
|
b583590a64 | ||
|
|
a28c63168a | ||
|
|
620422350f | ||
|
|
b77cc3c33b | ||
|
|
71bf9b4887 | ||
|
|
9039d401da | ||
|
|
74a0a93201 | ||
|
|
522571f0b3 | ||
|
|
123c49c22d | ||
|
|
1ff88d29be | ||
|
|
63d5a2a1be | ||
|
|
1e9a6cb06b | ||
|
|
31748aa660 | ||
|
|
d0c6ea6a63 | ||
|
|
7ffe286a56 | ||
|
|
b99b30163b | ||
|
|
83b4f1e660 | ||
|
|
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 |
21
.github/workflows/build.yml
vendored
21
.github/workflows/build.yml
vendored
@@ -18,13 +18,13 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: 删除工作流运行
|
# - name: 删除工作流运行
|
||||||
uses: Mattraks/delete-workflow-runs@v2
|
# uses: Mattraks/delete-workflow-runs@v2
|
||||||
with:
|
# with:
|
||||||
token: ${{ github.token }}
|
# token: ${{ github.token }}
|
||||||
repository: ${{ github.repository }}
|
# repository: ${{ github.repository }}
|
||||||
retain_days: 0
|
# retain_days: 0
|
||||||
keep_minimum_runs: 1
|
# keep_minimum_runs: 1
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cd v2rayN &&
|
run: cd v2rayN &&
|
||||||
@@ -36,13 +36,12 @@ jobs:
|
|||||||
# 7z a -mx9 ..\v2rayN.7z $env:Wap_Project_Directory
|
# 7z a -mx9 ..\v2rayN.7z $env:Wap_Project_Directory
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: v2rayN
|
name: v2rayN
|
||||||
path:
|
path: |
|
||||||
.\v2rayN\v2rayN.zip
|
.\v2rayN\v2rayN.zip
|
||||||
|
|
||||||
|
|
||||||
# - name: Release
|
# - name: Release
|
||||||
# uses: softprops/action-gh-release@v1
|
# uses: softprops/action-gh-release@v1
|
||||||
# env:
|
# env:
|
||||||
@@ -58,4 +57,4 @@ jobs:
|
|||||||
# * This is an automated deployment of GitHub Actions, the change log should be updated manually soon
|
# * This is an automated deployment of GitHub Actions, the change log should be updated manually soon
|
||||||
|
|
||||||
# ## 更新日志
|
# ## 更新日志
|
||||||
# * 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新
|
# * 这是 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)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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.25.1" />
|
<PackageReference Include="Google.Protobuf" Version="3.28.0" />
|
||||||
<PackageReference Include="Grpc.Net.Client" Version="2.59.0" />
|
<PackageReference Include="Grpc.Net.Client" Version="2.65.0" />
|
||||||
<PackageReference Include="Grpc.Tools" Version="2.59.0">
|
<PackageReference Include="Grpc.Tools" Version="2.66.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>
|
||||||
|
|||||||
11
v2rayN/ServiceLib/Base/MyReactiveObject.cs
Normal file
11
v2rayN/ServiceLib/Base/MyReactiveObject.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace ServiceLib.Base
|
||||||
|
{
|
||||||
|
public class MyReactiveObject : ReactiveObject
|
||||||
|
{
|
||||||
|
protected static Config? _config;
|
||||||
|
protected Func<EViewAction, object?, Task<bool>>? _updateView;
|
||||||
|
protected NoticeHandler? _noticeHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
using Downloader;
|
using Downloader;
|
||||||
using System.IO;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace v2rayN.Base
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
internal class DownloaderHelper
|
public class DownloaderHelper
|
||||||
{
|
{
|
||||||
private static readonly Lazy<DownloaderHelper> _instance = new(() => new());
|
private static readonly Lazy<DownloaderHelper> _instance = new(() => new());
|
||||||
public static DownloaderHelper Instance => _instance.Value;
|
public static DownloaderHelper Instance => _instance.Value;
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -57,7 +56,7 @@ 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));
|
||||||
}
|
}
|
||||||
@@ -120,11 +119,11 @@ namespace v2rayN.Base
|
|||||||
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
@@ -169,11 +168,15 @@ namespace v2rayN.Base
|
|||||||
{
|
{
|
||||||
progress.Report(101);
|
progress.Report(101);
|
||||||
}
|
}
|
||||||
|
else if (value.Error != null)
|
||||||
|
{
|
||||||
|
throw value.Error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using var cts = new CancellationTokenSource();
|
using var cts = new CancellationTokenSource();
|
||||||
await downloader.DownloadFileTaskAsync(url, fileName, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token);
|
await downloader.DownloadFileTaskAsync(url, fileName, cts.Token);
|
||||||
|
|
||||||
downloadOpt = null;
|
downloadOpt = null;
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
using System.IO;
|
using System.IO.Compression;
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace v2rayN.Tool
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
public static class FileManager
|
public static class FileManager
|
||||||
{
|
{
|
||||||
@@ -15,12 +14,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 +29,23 @@ namespace v2rayN.Tool
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UncompressedFile(string fileName, string toPath, string? toName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FileInfo fileInfo = new(fileName);
|
||||||
|
using FileStream originalFileStream = fileInfo.OpenRead();
|
||||||
|
using FileStream decompressedFileStream = File.Create(toName != null ? Path.Combine(toPath, toName) : toPath);
|
||||||
|
using GZipStream decompressionStream = new(originalFileStream, CompressionMode.Decompress);
|
||||||
|
decompressionStream.CopyTo(decompressedFileStream);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +64,7 @@ namespace v2rayN.Tool
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,13 +90,27 @@ 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 true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ZipFile.CreateFromDirectory(sourceDirectoryName, destinationArchiveFileName);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
using System.IO;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace v2rayN.Base
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -21,26 +20,57 @@ namespace v2rayN.Base
|
|||||||
|
|
||||||
private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
|
private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
|
||||||
|
|
||||||
|
public async Task<string?> TryGetAsync(string url)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(url))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpResponseMessage response = await httpClient.GetAsync(url);
|
||||||
|
return await response.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task PatchAsync(string url, Dictionary<string, string> headers)
|
||||||
|
{
|
||||||
|
var myContent = JsonUtils.Serialize(headers);
|
||||||
|
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
|
||||||
|
var byteContent = new ByteArrayContent(buffer);
|
||||||
|
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||||
|
|
||||||
|
await httpClient.PatchAsync(url, byteContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAsync(string url)
|
||||||
|
{
|
||||||
|
await httpClient.DeleteAsync(url);
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double>? progress, CancellationToken token = default)
|
public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double>? progress, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(url);
|
ArgumentNullException.ThrowIfNull(url);
|
||||||
@@ -76,19 +106,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));
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace v2rayN
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* See:
|
* See:
|
||||||
@@ -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;
|
||||||
133
v2rayN/ServiceLib/Common/JsonUtils.cs
Normal file
133
v2rayN/ServiceLib/Common/JsonUtils.cs
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace ServiceLib.Common
|
||||||
|
{
|
||||||
|
public 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)
|
||||||
|
{
|
||||||
|
if (filePath is null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using FileStream file = File.Create(filePath);
|
||||||
|
|
||||||
|
var options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
|
||||||
|
};
|
||||||
|
|
||||||
|
JsonSerializer.Serialize(file, obj, options);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
using NLog;
|
using NLog;
|
||||||
using NLog.Config;
|
using NLog.Config;
|
||||||
using NLog.Targets;
|
using NLog.Targets;
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace v2rayN.Tool
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
public class Logging
|
public class Logging
|
||||||
{
|
{
|
||||||
@@ -51,5 +50,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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
15
v2rayN/ServiceLib/Common/QRCodeHelper.cs
Normal file
15
v2rayN/ServiceLib/Common/QRCodeHelper.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using QRCoder;
|
||||||
|
|
||||||
|
namespace ServiceLib.Common
|
||||||
|
{
|
||||||
|
public class QRCodeHelper
|
||||||
|
{
|
||||||
|
public static byte[]? GenQRCode(string? url)
|
||||||
|
{
|
||||||
|
using QRCodeGenerator qrGenerator = new();
|
||||||
|
using QRCodeData qrCodeData = qrGenerator.CreateQrCode(url ?? string.Empty, QRCodeGenerator.ECCLevel.Q);
|
||||||
|
using PngByteQRCode qrCode = new(qrCodeData);
|
||||||
|
return qrCode.GetGraphic(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace v2rayN.Tool
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using v2rayN.Base;
|
namespace ServiceLib.Common
|
||||||
|
|
||||||
namespace v2rayN.Tool
|
|
||||||
{
|
{
|
||||||
public class SemanticVersion
|
public class SemanticVersion
|
||||||
{
|
{
|
||||||
@@ -29,7 +27,7 @@ namespace v2rayN.Tool
|
|||||||
this.minor = int.Parse(parts[1]);
|
this.minor = int.Parse(parts[1]);
|
||||||
this.patch = 0;
|
this.patch = 0;
|
||||||
}
|
}
|
||||||
else if (parts.Length == 3)
|
else if (parts.Length == 3 || parts.Length == 4)
|
||||||
{
|
{
|
||||||
this.major = int.Parse(parts[0]);
|
this.major = int.Parse(parts[0]);
|
||||||
this.minor = int.Parse(parts[1]);
|
this.minor = int.Parse(parts[1]);
|
||||||
@@ -1,20 +1,21 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
namespace v2rayN.Base
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
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,9 +1,8 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace v2rayN.Base
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
internal static class StringEx
|
public static class StringEx
|
||||||
{
|
{
|
||||||
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
|
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
|
||||||
{
|
{
|
||||||
@@ -80,5 +79,15 @@ namespace v2rayN.Base
|
|||||||
|
|
||||||
return char.ToUpper(value[0]) + value.Substring(1);
|
return char.ToUpper(value[0]) + value.Substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string AppendQuotes(this string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"\"{value}\"";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
58
v2rayN/ServiceLib/Common/YamlUtils.cs
Normal file
58
v2rayN/ServiceLib/Common/YamlUtils.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using YamlDotNet.Serialization;
|
||||||
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
|
||||||
|
namespace ServiceLib.Common
|
||||||
|
{
|
||||||
|
public class YamlUtils
|
||||||
|
{
|
||||||
|
#region YAML
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 反序列化成对象
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="str"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T FromYaml<T>(string str)
|
||||||
|
{
|
||||||
|
var deserializer = new DeserializerBuilder()
|
||||||
|
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||||
|
.Build();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
T obj = deserializer.Deserialize<T>(str);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("FromYaml", ex);
|
||||||
|
return deserializer.Deserialize<T>("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 序列化
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string ToYaml(Object obj)
|
||||||
|
{
|
||||||
|
var serializer = new SerializerBuilder()
|
||||||
|
.WithNamingConvention(HyphenatedNamingConvention.Instance)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
string result = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = serializer.Serialize(obj);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion YAML
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Enums
|
||||||
{
|
{
|
||||||
public enum EConfigType
|
public enum EConfigType
|
||||||
{
|
{
|
||||||
@@ -8,6 +8,9 @@
|
|||||||
Socks = 4,
|
Socks = 4,
|
||||||
VLESS = 5,
|
VLESS = 5,
|
||||||
Trojan = 6,
|
Trojan = 6,
|
||||||
Hysteria2 = 7
|
Hysteria2 = 7,
|
||||||
|
Tuic = 8,
|
||||||
|
Wireguard = 9,
|
||||||
|
Http = 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Enums
|
||||||
{
|
{
|
||||||
public enum ECoreType
|
public enum ECoreType
|
||||||
{
|
{
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
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,
|
||||||
9
v2rayN/ServiceLib/Enums/EGirdOrientation.cs
Normal file
9
v2rayN/ServiceLib/Enums/EGirdOrientation.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace ServiceLib.Enums
|
||||||
|
{
|
||||||
|
public enum EGirdOrientation
|
||||||
|
{
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
Tab,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Enums
|
||||||
{
|
{
|
||||||
public enum EGlobalHotkey
|
public enum EGlobalHotkey
|
||||||
{
|
{
|
||||||
14
v2rayN/ServiceLib/Enums/EInboundProtocol.cs
Normal file
14
v2rayN/ServiceLib/Enums/EInboundProtocol.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace ServiceLib.Enums
|
||||||
|
{
|
||||||
|
public enum EInboundProtocol
|
||||||
|
{
|
||||||
|
socks = 0,
|
||||||
|
http,
|
||||||
|
socks2,
|
||||||
|
http2,
|
||||||
|
pac,
|
||||||
|
api,
|
||||||
|
api2,
|
||||||
|
speedtest = 21
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Enums
|
||||||
{
|
{
|
||||||
public enum EMove
|
public enum EMove
|
||||||
{
|
{
|
||||||
10
v2rayN/ServiceLib/Enums/ERuleMode.cs
Normal file
10
v2rayN/ServiceLib/Enums/ERuleMode.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace ServiceLib.Enums
|
||||||
|
{
|
||||||
|
public enum ERuleMode
|
||||||
|
{
|
||||||
|
Rule = 0,
|
||||||
|
Global = 1,
|
||||||
|
Direct = 2,
|
||||||
|
Unchanged = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Enums
|
||||||
{
|
{
|
||||||
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 ServiceLib.Enums
|
||||||
{
|
{
|
||||||
public enum ESpeedActionType
|
public enum ESpeedActionType
|
||||||
{
|
{
|
||||||
Ping,
|
|
||||||
Tcping,
|
Tcping,
|
||||||
Realping,
|
Realping,
|
||||||
Speedtest,
|
Speedtest,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Enums
|
||||||
{
|
{
|
||||||
public enum ESysProxyType
|
public enum ESysProxyType
|
||||||
{
|
{
|
||||||
15
v2rayN/ServiceLib/Enums/ETransport.cs
Normal file
15
v2rayN/ServiceLib/Enums/ETransport.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace ServiceLib.Enums
|
||||||
|
{
|
||||||
|
public enum ETransport
|
||||||
|
{
|
||||||
|
tcp,
|
||||||
|
kcp,
|
||||||
|
ws,
|
||||||
|
httpupgrade,
|
||||||
|
splithttp,
|
||||||
|
h2,
|
||||||
|
http,
|
||||||
|
quic,
|
||||||
|
grpc
|
||||||
|
}
|
||||||
|
}
|
||||||
45
v2rayN/ServiceLib/Enums/EViewAction.cs
Normal file
45
v2rayN/ServiceLib/Enums/EViewAction.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
namespace ServiceLib.Enums
|
||||||
|
{
|
||||||
|
public enum EViewAction
|
||||||
|
{
|
||||||
|
CloseWindow,
|
||||||
|
ShowYesNo,
|
||||||
|
SaveFileDialog,
|
||||||
|
AddBatchRoutingRulesYesNo,
|
||||||
|
AdjustMainLvColWidth,
|
||||||
|
UpdateSysProxy,
|
||||||
|
SetClipboardData,
|
||||||
|
AddServerViaClipboard,
|
||||||
|
ImportRulesFromClipboard,
|
||||||
|
ProfilesFocus,
|
||||||
|
ShareSub,
|
||||||
|
ShareServer,
|
||||||
|
ShowHideWindow,
|
||||||
|
ScanScreenTask,
|
||||||
|
Shutdown,
|
||||||
|
BrowseServer,
|
||||||
|
ImportRulesFromFile,
|
||||||
|
SubEditWindow,
|
||||||
|
RoutingRuleSettingWindow,
|
||||||
|
RoutingRuleDetailsWindow,
|
||||||
|
AddServerWindow,
|
||||||
|
AddServer2Window,
|
||||||
|
DNSSettingWindow,
|
||||||
|
RoutingSettingWindow,
|
||||||
|
OptionSettingWindow,
|
||||||
|
GlobalHotkeySettingWindow,
|
||||||
|
SubSettingWindow,
|
||||||
|
DispatcherSpeedTest,
|
||||||
|
DispatcherRefreshConnections,
|
||||||
|
DispatcherRefreshProxyGroups,
|
||||||
|
DispatcherProxiesDelayTest,
|
||||||
|
DispatcherStatistics,
|
||||||
|
DispatcherServerAvailability,
|
||||||
|
DispatcherReload,
|
||||||
|
DispatcherRefreshServersBiz,
|
||||||
|
DispatcherRefreshIcon,
|
||||||
|
DispatcherCheckUpdate,
|
||||||
|
DispatcherCheckUpdateFinished,
|
||||||
|
DispatcherShowMsg,
|
||||||
|
}
|
||||||
|
}
|
||||||
3
v2rayN/ServiceLib/FodyWeavers.xml
Normal file
3
v2rayN/ServiceLib/FodyWeavers.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||||
|
<ReactiveUI />
|
||||||
|
</Weavers>
|
||||||
201
v2rayN/ServiceLib/Global.cs
Normal file
201
v2rayN/ServiceLib/Global.cs
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
namespace ServiceLib
|
||||||
|
{
|
||||||
|
public class Global
|
||||||
|
{
|
||||||
|
#region const
|
||||||
|
|
||||||
|
public const string AppName = "v2rayN";
|
||||||
|
public const string GithubUrl = "https://github.com";
|
||||||
|
public const string GithubApiUrl = "https://api.github.com/repos";
|
||||||
|
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 NUrl = @"https://github.com/2dust/v2rayN/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 MihomoCoreUrl = "https://github.com/MetaCubeX/mihomo/releases";
|
||||||
|
public const string HysteriaCoreUrl = "https://github.com/apernet/hysteria/releases";
|
||||||
|
public const string NaiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
|
||||||
|
public const string TuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
|
||||||
|
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 JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
|
||||||
|
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
||||||
|
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
|
||||||
|
|
||||||
|
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
||||||
|
public const string ConfigFileName = "guiNConfig.json";
|
||||||
|
public const string CoreConfigFileName = "config.json";
|
||||||
|
public const string CorePreConfigFileName = "configPre.json";
|
||||||
|
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
|
||||||
|
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
|
||||||
|
public const string ClashMixinConfigFileName = "Mixin.yaml";
|
||||||
|
public const string V2raySampleClient = "ServiceLib.Sample.SampleClientConfig";
|
||||||
|
public const string SingboxSampleClient = "ServiceLib.Sample.SingboxSampleClientConfig";
|
||||||
|
public const string V2raySampleHttpRequestFileName = "ServiceLib.Sample.SampleHttpRequest";
|
||||||
|
public const string V2raySampleHttpResponseFileName = "ServiceLib.Sample.SampleHttpResponse";
|
||||||
|
public const string V2raySampleInbound = "ServiceLib.Sample.SampleInbound";
|
||||||
|
public const string V2raySampleOutbound = "ServiceLib.Sample.SampleOutbound";
|
||||||
|
public const string SingboxSampleOutbound = "ServiceLib.Sample.SingboxSampleOutbound";
|
||||||
|
public const string CustomRoutingFileName = "ServiceLib.Sample.custom_routing_";
|
||||||
|
public const string TunSingboxDNSFileName = "ServiceLib.Sample.tun_singbox_dns";
|
||||||
|
public const string TunSingboxInboundFileName = "ServiceLib.Sample.tun_singbox_inbound";
|
||||||
|
public const string TunSingboxRulesFileName = "ServiceLib.Sample.tun_singbox_rules";
|
||||||
|
public const string DNSV2rayNormalFileName = "ServiceLib.Sample.dns_v2ray_normal";
|
||||||
|
public const string DNSSingboxNormalFileName = "ServiceLib.Sample.dns_singbox_normal";
|
||||||
|
public const string ClashMixinYaml = "ServiceLib.Sample.clash_mixin_yaml";
|
||||||
|
public const string ClashTunYaml = "ServiceLib.Sample.clash_tun_yaml";
|
||||||
|
|
||||||
|
public const string DefaultSecurity = "auto";
|
||||||
|
public const string DefaultNetwork = "tcp";
|
||||||
|
public const string TcpHeaderHttp = "http";
|
||||||
|
public const string None = "none";
|
||||||
|
public const string ProxyTag = "proxy";
|
||||||
|
public const string DirectTag = "direct";
|
||||||
|
public const string BlockTag = "block";
|
||||||
|
public const string StreamSecurity = "tls";
|
||||||
|
public const string StreamSecurityReality = "reality";
|
||||||
|
public const string Loopback = "127.0.0.1";
|
||||||
|
public const string InboundAPIProtocol = "dokodemo-door";
|
||||||
|
public const string HttpProtocol = "http://";
|
||||||
|
public const string HttpsProtocol = "https://";
|
||||||
|
public const string SocksProtocol = "socks://";
|
||||||
|
|
||||||
|
public const string UserEMail = "t@t.tt";
|
||||||
|
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||||
|
public const string AutoRunName = "v2rayNAutoRun";
|
||||||
|
public const string CustomIconName = "v2rayN.ico";
|
||||||
|
public const string 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 GrpcGunMode = "gun";
|
||||||
|
public const string GrpcMultiMode = "multi";
|
||||||
|
public const int MaxPort = 65536;
|
||||||
|
public const string CommandClearMsg = "CommandClearMsg";
|
||||||
|
public const string CommandSendMsgView = "CommandSendMsgView";
|
||||||
|
public const string CommandSendSnackMsg = "CommandSendSnackMsg";
|
||||||
|
public const string CommandStopSpeedTest = "CommandStopSpeedTest";
|
||||||
|
public const string CommandRefreshProfiles = "CommandRefreshProfiles";
|
||||||
|
public const string DelayUnit = "";
|
||||||
|
public const string SpeedUnit = "";
|
||||||
|
public const int MinFontSize = 10;
|
||||||
|
public const string RebootAs = "rebootas";
|
||||||
|
|
||||||
|
public static readonly List<string> IEProxyProtocols = new() {
|
||||||
|
"{ip}:{http_port}",
|
||||||
|
"socks={ip}:{socks_port}",
|
||||||
|
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
|
||||||
|
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly List<string> SubConvertUrls = new List<string> {
|
||||||
|
@"https://sub.xeton.dev/sub?url={0}",
|
||||||
|
@"https://api.dler.io/sub?url={0}",
|
||||||
|
@"http://127.0.0.1:25500/sub?url={0}",
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly List<string> SubConvertConfig = new List<string> {
|
||||||
|
@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly List<string> SubConvertTargets = new List<string> {
|
||||||
|
"",
|
||||||
|
"mixed",
|
||||||
|
"v2ray",
|
||||||
|
"clash",
|
||||||
|
"ss",
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly List<string> 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/10mb.test"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly List<string> SpeedPingTestUrls = new() {
|
||||||
|
@"https://www.google.com/generate_204",
|
||||||
|
@"https://www.gstatic.com/generate_204",
|
||||||
|
@"https://www.apple.com/library/test/success.html",
|
||||||
|
@"http://www.msftconnecttest.com/connecttest.txt",
|
||||||
|
};
|
||||||
|
|
||||||
|
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" },
|
||||||
|
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
|
||||||
|
{"safari","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15" },
|
||||||
|
{"edge","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70" },
|
||||||
|
{"none",""}
|
||||||
|
};
|
||||||
|
|
||||||
|
public const string Hysteria2ProtocolShare = "hy2://";
|
||||||
|
|
||||||
|
public static readonly Dictionary<EConfigType, string> ProtocolShares = new()
|
||||||
|
{
|
||||||
|
{EConfigType.VMess,"vmess://"},
|
||||||
|
{EConfigType.Shadowsocks,"ss://"},
|
||||||
|
{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", "splithttp", "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> SingboxDomainStrategy4Out = new() { "ipv4_only", "prefer_ipv4", "prefer_ipv6", "ipv6_only", "" };
|
||||||
|
public static readonly List<string> DomainDNSAddress = ["223.5.5.5", "223.6.6.6", "localhost"];
|
||||||
|
public static readonly List<string> SingboxDomainDNSAddress = ["223.5.5.5", "223.6.6.6", "dhcp://auto"];
|
||||||
|
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
|
||||||
|
public static readonly List<string> Alpns = new() { "h3", "h2", "http/1.1", "h3,h2", "h2,http/1.1", "h3,h2,http/1.1", "" };
|
||||||
|
public static readonly List<string> LogLevels = new() { "debug", "info", "warning", "error", "none" };
|
||||||
|
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
|
||||||
|
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
|
||||||
|
public static readonly List<string> RuleNetworks = new() { "", "tcp", "udp", "tcp,udp" };
|
||||||
|
public static readonly List<string> destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"];
|
||||||
|
public static readonly List<string> TunMtus = new() { "1280", "1408", "1500", "9000" };
|
||||||
|
public static readonly List<string> TunStacks = new() { "gvisor", "system" };
|
||||||
|
public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
|
||||||
|
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
|
||||||
|
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
|
||||||
|
|
||||||
|
public static readonly List<string> allowSelectType = new List<string> { "selector", "urltest", "loadbalance", "fallback" };
|
||||||
|
public static readonly List<string> notAllowTestType = new List<string> { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
|
||||||
|
public static readonly List<string> proxyVehicleType = new List<string> { "file", "http" };
|
||||||
|
|
||||||
|
#endregion const
|
||||||
|
}
|
||||||
|
}
|
||||||
9
v2rayN/ServiceLib/GlobalUsings.cs
Normal file
9
v2rayN/ServiceLib/GlobalUsings.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
global using ServiceLib.Base;
|
||||||
|
global using ServiceLib.Common;
|
||||||
|
global using ServiceLib.Enums;
|
||||||
|
global using ServiceLib.Handler;
|
||||||
|
global using ServiceLib.Handler.CoreConfig;
|
||||||
|
global using ServiceLib.Handler.Fmt;
|
||||||
|
global using ServiceLib.Handler.Statistics;
|
||||||
|
global using ServiceLib.Models;
|
||||||
|
global using ServiceLib.Resx;
|
||||||
206
v2rayN/ServiceLib/Handler/ClashApiHandler.cs
Normal file
206
v2rayN/ServiceLib/Handler/ClashApiHandler.cs
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
using static ServiceLib.Models.ClashProxies;
|
||||||
|
|
||||||
|
namespace ServiceLib.Handler
|
||||||
|
{
|
||||||
|
public sealed class ClashApiHandler
|
||||||
|
{
|
||||||
|
private static readonly Lazy<ClashApiHandler> instance = new(() => new());
|
||||||
|
public static ClashApiHandler Instance => instance.Value;
|
||||||
|
|
||||||
|
private Dictionary<String, ProxiesItem>? _proxies;
|
||||||
|
public Dictionary<string, object> ProfileContent { get; set; }
|
||||||
|
|
||||||
|
public void GetClashProxies(Config config, Action<ClashProxies, ClashProviders> update)
|
||||||
|
{
|
||||||
|
Task.Run(() => GetClashProxiesAsync(config, update));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetClashProxiesAsync(Config config, Action<ClashProxies, ClashProviders> update)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/proxies";
|
||||||
|
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
||||||
|
var clashProxies = JsonUtils.Deserialize<ClashProxies>(result);
|
||||||
|
|
||||||
|
var url2 = $"{GetApiUrl()}/providers/proxies";
|
||||||
|
var result2 = await HttpClientHelper.Instance.TryGetAsync(url2);
|
||||||
|
var clashProviders = JsonUtils.Deserialize<ClashProviders>(result2);
|
||||||
|
|
||||||
|
if (clashProxies != null || clashProviders != null)
|
||||||
|
{
|
||||||
|
_proxies = clashProxies?.proxies;
|
||||||
|
update(clashProxies, clashProviders);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Task.Delay(5000).Wait();
|
||||||
|
}
|
||||||
|
update(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> update)
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
if (blAll)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
if (_proxies != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Task.Delay(5000).Wait();
|
||||||
|
}
|
||||||
|
if (_proxies == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lstProxy = new List<ClashProxyModel>();
|
||||||
|
foreach (KeyValuePair<string, ProxiesItem> kv in _proxies)
|
||||||
|
{
|
||||||
|
if (Global.notAllowTestType.Contains(kv.Value.type.ToLower()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lstProxy.Add(new ClashProxyModel()
|
||||||
|
{
|
||||||
|
name = kv.Value.name,
|
||||||
|
type = kv.Value.type.ToLower(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstProxy == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var urlBase = $"{GetApiUrl()}/proxies";
|
||||||
|
urlBase += @"/{0}/delay?timeout=10000&url=" + LazyConfig.Instance.Config.speedTestItem.speedPingTestUrl;
|
||||||
|
|
||||||
|
List<Task> tasks = new List<Task>();
|
||||||
|
foreach (var it in lstProxy)
|
||||||
|
{
|
||||||
|
if (Global.notAllowTestType.Contains(it.type.ToLower()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var name = it.name;
|
||||||
|
var url = string.Format(urlBase, name);
|
||||||
|
tasks.Add(Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
||||||
|
update(it, result);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Task.WaitAll(tasks.ToArray());
|
||||||
|
|
||||||
|
Task.Delay(1000).Wait();
|
||||||
|
update(null, "");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ProxiesItem>? GetClashProxyGroups()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fileContent = ProfileContent;
|
||||||
|
if (fileContent is null || fileContent?.ContainsKey("proxy-groups") == false)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return JsonUtils.Deserialize<List<ProxiesItem>>(JsonUtils.Serialize(fileContent["proxy-groups"]));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("GetClashProxyGroups", ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ClashSetActiveProxy(string name, string nameNode)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/proxies/{name}";
|
||||||
|
Dictionary<string, string> headers = new Dictionary<string, string>();
|
||||||
|
headers.Add("name", nameNode);
|
||||||
|
await HttpClientHelper.Instance.PutAsync(url, headers);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClashConfigUpdate(Dictionary<string, string> headers)
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
if (_proxies == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var urlBase = $"{GetApiUrl()}/configs";
|
||||||
|
|
||||||
|
await HttpClientHelper.Instance.PatchAsync(urlBase, headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ClashConfigReload(string filePath)
|
||||||
|
{
|
||||||
|
ClashConnectionClose("");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/configs?force=true";
|
||||||
|
Dictionary<string, string> headers = new Dictionary<string, string>();
|
||||||
|
headers.Add("path", filePath);
|
||||||
|
await HttpClientHelper.Instance.PutAsync(url, headers);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetClashConnections(Config config, Action<ClashConnections> update)
|
||||||
|
{
|
||||||
|
Task.Run(() => GetClashConnectionsAsync(config, update));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetClashConnectionsAsync(Config config, Action<ClashConnections> update)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/connections";
|
||||||
|
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
||||||
|
var clashConnections = JsonUtils.Deserialize<ClashConnections>(result);
|
||||||
|
|
||||||
|
update(clashConnections);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ClashConnectionClose(string id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{GetApiUrl()}/connections/{id}";
|
||||||
|
await HttpClientHelper.Instance.DeleteAsync(url);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetApiUrl()
|
||||||
|
{
|
||||||
|
return $"{Global.HttpProtocol}{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
265
v2rayN/ServiceLib/Handler/CoreConfig/CoreConfigClash.cs
Normal file
265
v2rayN/ServiceLib/Handler/CoreConfig/CoreConfigClash.cs
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
namespace ServiceLib.Handler.CoreConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Core configuration file processing class
|
||||||
|
/// </summary>
|
||||||
|
public class CoreConfigClash
|
||||||
|
{
|
||||||
|
private Config _config;
|
||||||
|
|
||||||
|
public CoreConfigClash(Config config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成配置文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node"></param>
|
||||||
|
/// <param name="fileName"></param>
|
||||||
|
/// <param name="msg"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public int GenerateClientCustomConfig(ProfileItem node, string? fileName, out string msg)
|
||||||
|
{
|
||||||
|
if (node == null || fileName is null)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (node == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
{
|
||||||
|
File.Delete(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
string addressFileName = node.address;
|
||||||
|
if (string.IsNullOrEmpty(addressFileName))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!File.Exists(addressFileName))
|
||||||
|
{
|
||||||
|
addressFileName = Path.Combine(Utils.GetConfigPath(), addressFileName);
|
||||||
|
}
|
||||||
|
if (!File.Exists(addressFileName))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedReadConfiguration + "1";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
string tagYamlStr1 = "!<str>";
|
||||||
|
string tagYamlStr2 = "__strn__";
|
||||||
|
string tagYamlStr3 = "!!str";
|
||||||
|
var txtFile = File.ReadAllText(addressFileName);
|
||||||
|
txtFile = txtFile.Replace(tagYamlStr1, tagYamlStr2);
|
||||||
|
|
||||||
|
var fileContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
|
||||||
|
if (fileContent == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedConversionConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//port
|
||||||
|
fileContent["port"] = LazyConfig.Instance.GetLocalPort(EInboundProtocol.http);
|
||||||
|
//socks-port
|
||||||
|
fileContent["socks-port"] = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||||
|
//log-level
|
||||||
|
fileContent["log-level"] = GetLogLevel(_config.coreBasicItem.loglevel);
|
||||||
|
|
||||||
|
//external-controller
|
||||||
|
fileContent["external-controller"] = $"{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
|
||||||
|
//allow-lan
|
||||||
|
if (_config.inbound[0].allowLANConn)
|
||||||
|
{
|
||||||
|
fileContent["allow-lan"] = "true";
|
||||||
|
fileContent["bind-address"] = "*";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileContent["allow-lan"] = "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
//ipv6
|
||||||
|
fileContent["ipv6"] = _config.clashUIItem.enableIPv6;
|
||||||
|
|
||||||
|
//mode
|
||||||
|
if (!fileContent.ContainsKey("mode"))
|
||||||
|
{
|
||||||
|
fileContent["mode"] = ERuleMode.Rule.ToString().ToLower();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_config.clashUIItem.ruleMode != ERuleMode.Unchanged)
|
||||||
|
{
|
||||||
|
fileContent["mode"] = _config.clashUIItem.ruleMode.ToString().ToLower();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//enable tun mode
|
||||||
|
if (_config.tunModeItem.enableTun)
|
||||||
|
{
|
||||||
|
string tun = Utils.GetEmbedText(Global.ClashTunYaml);
|
||||||
|
if (!string.IsNullOrEmpty(tun))
|
||||||
|
{
|
||||||
|
var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun);
|
||||||
|
if (tunContent != null)
|
||||||
|
fileContent["tun"] = tunContent["tun"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Mixin
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MixinContent(fileContent, node);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("GenerateClientConfigClash-Mixin", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
var txtFileNew = YamlUtils.ToYaml(fileContent).Replace(tagYamlStr2, tagYamlStr3);
|
||||||
|
File.WriteAllText(fileName, txtFileNew);
|
||||||
|
//check again
|
||||||
|
if (!File.Exists(fileName))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedReadConfiguration + "2";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClashApiHandler.Instance.ProfileContent = fileContent;
|
||||||
|
|
||||||
|
msg = string.Format(ResUI.SuccessfulConfiguration, $"{node.GetSummary()}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("GenerateClientConfigClash", ex);
|
||||||
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MixinContent(Dictionary<string, object> fileContent, ProfileItem node)
|
||||||
|
{
|
||||||
|
//if (!_config.clashUIItem.enableMixinContent)
|
||||||
|
//{
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
var path = Utils.GetConfigPath(Global.ClashMixinConfigFileName);
|
||||||
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var txtFile = File.ReadAllText(Utils.GetConfigPath(Global.ClashMixinConfigFileName));
|
||||||
|
|
||||||
|
var mixinContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
|
||||||
|
if (mixinContent == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (var item in mixinContent)
|
||||||
|
{
|
||||||
|
if (!_config.tunModeItem.enableTun && item.Key == "tun")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.Key.StartsWith("prepend-")
|
||||||
|
|| item.Key.StartsWith("append-")
|
||||||
|
|| item.Key.StartsWith("removed-"))
|
||||||
|
{
|
||||||
|
ModifyContentMerge(fileContent, item.Key, item.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileContent[item.Key] = item.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ModifyContentMerge(Dictionary<string, object> fileContent, string key, object value)
|
||||||
|
{
|
||||||
|
bool blPrepend = false;
|
||||||
|
bool blRemoved = false;
|
||||||
|
if (key.StartsWith("prepend-"))
|
||||||
|
{
|
||||||
|
blPrepend = true;
|
||||||
|
key = key.Replace("prepend-", "");
|
||||||
|
}
|
||||||
|
else if (key.StartsWith("append-"))
|
||||||
|
{
|
||||||
|
blPrepend = false;
|
||||||
|
key = key.Replace("append-", "");
|
||||||
|
}
|
||||||
|
else if (key.StartsWith("removed-"))
|
||||||
|
{
|
||||||
|
blRemoved = true;
|
||||||
|
key = key.Replace("removed-", "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!blRemoved && !fileContent.ContainsKey(key))
|
||||||
|
{
|
||||||
|
fileContent.Add(key, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var lstOri = (List<object>)fileContent[key];
|
||||||
|
var lstValue = (List<object>)value;
|
||||||
|
|
||||||
|
if (blRemoved)
|
||||||
|
{
|
||||||
|
foreach (var item in lstValue)
|
||||||
|
{
|
||||||
|
lstOri.RemoveAll(t => t.ToString().StartsWith(item.ToString()));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blPrepend)
|
||||||
|
{
|
||||||
|
lstValue.Reverse();
|
||||||
|
foreach (var item in lstValue)
|
||||||
|
{
|
||||||
|
lstOri.Insert(0, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var item in lstValue)
|
||||||
|
{
|
||||||
|
lstOri.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetLogLevel(string level)
|
||||||
|
{
|
||||||
|
if (level == "none")
|
||||||
|
{
|
||||||
|
return "silent";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
using System.IO;
|
namespace ServiceLib.Handler.CoreConfig
|
||||||
using v2rayN.Mode;
|
|
||||||
using v2rayN.Resx;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Core configuration file processing class
|
/// Core configuration file processing class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class CoreConfigHandler
|
public class CoreConfigHandler
|
||||||
{
|
{
|
||||||
public static int GenerateClientConfig(ProfileItem node, string? fileName, out string msg, out string content)
|
public static int GenerateClientConfig(ProfileItem node, string? fileName, out string msg, out string content)
|
||||||
{
|
{
|
||||||
@@ -19,14 +15,27 @@ namespace v2rayN.Handler
|
|||||||
msg = ResUI.CheckServerSettings;
|
msg = ResUI.CheckServerSettings;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
var config = LazyConfig.Instance.GetConfig();
|
var config = LazyConfig.Instance.Config;
|
||||||
|
|
||||||
msg = ResUI.InitialConfiguration;
|
msg = ResUI.InitialConfiguration;
|
||||||
if (node.configType == EConfigType.Custom)
|
if (node.configType == EConfigType.Custom)
|
||||||
{
|
{
|
||||||
return GenerateClientCustomConfig(node, fileName, out msg);
|
if (node.coreType is ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo)
|
||||||
|
{
|
||||||
|
var configGenClash = new CoreConfigClash(config);
|
||||||
|
return configGenClash.GenerateClientCustomConfig(node, fileName, out msg);
|
||||||
|
}
|
||||||
|
if (node.coreType is ECoreType.sing_box)
|
||||||
|
{
|
||||||
|
var configGenSingbox = new CoreConfigSingbox(config);
|
||||||
|
return configGenSingbox.GenerateClientCustomConfig(node, fileName, out msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GenerateClientCustomConfig(node, fileName, out msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (config.tunModeItem.enableTun || LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box)
|
else if (LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box)
|
||||||
{
|
{
|
||||||
var configGenSingbox = new CoreConfigSingbox(config);
|
var configGenSingbox = new CoreConfigSingbox(config);
|
||||||
if (configGenSingbox.GenerateClientConfigContent(node, out SingboxConfig? singboxConfig, out msg) != 0)
|
if (configGenSingbox.GenerateClientConfigContent(node, out SingboxConfig? singboxConfig, out msg) != 0)
|
||||||
@@ -35,11 +44,11 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
content = Utils.ToJson(singboxConfig);
|
content = JsonUtils.Serialize(singboxConfig);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Utils.ToJsonFile(singboxConfig, fileName, false);
|
JsonUtils.ToFile(singboxConfig, fileName, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -51,17 +60,17 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
content = Utils.ToJson(v2rayConfig);
|
content = JsonUtils.Serialize(v2rayConfig);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Utils.ToJsonFile(v2rayConfig, fileName, false);
|
JsonUtils.ToFile(v2rayConfig, fileName, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("GenerateClientConfig", ex);
|
Logging.SaveLog("GenerateClientConfig", ex);
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -104,55 +113,59 @@ namespace v2rayN.Handler
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//overwrite port
|
|
||||||
if (node.preSocksPort <= 0)
|
|
||||||
{
|
|
||||||
var fileContent = File.ReadAllLines(fileName).ToList();
|
|
||||||
var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
|
||||||
switch (coreType)
|
|
||||||
{
|
|
||||||
case ECoreType.v2fly:
|
|
||||||
case ECoreType.SagerNet:
|
|
||||||
case ECoreType.Xray:
|
|
||||||
case ECoreType.v2fly_v5:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ECoreType.clash:
|
|
||||||
case ECoreType.clash_meta:
|
|
||||||
//remove the original
|
|
||||||
var indexPort = fileContent.FindIndex(t => t.Contains("port:"));
|
|
||||||
if (indexPort >= 0)
|
|
||||||
{
|
|
||||||
fileContent.RemoveAt(indexPort);
|
|
||||||
}
|
|
||||||
indexPort = fileContent.FindIndex(t => t.Contains("socks-port:"));
|
|
||||||
if (indexPort >= 0)
|
|
||||||
{
|
|
||||||
fileContent.RemoveAt(indexPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
fileContent.Add($"port: {LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}");
|
|
||||||
fileContent.Add($"socks-port: {LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
File.WriteAllLines(fileName, fileContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog("GenerateClientCustomConfig", ex);
|
Logging.SaveLog("GenerateClientCustomConfig", ex);
|
||||||
msg = ResUI.FailedGenDefaultConfiguration;
|
msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GenerateClientSpeedtestConfigString(Config config, List<ServerTestItem> selecteds, out string msg)
|
public static int GenerateClientSpeedtestConfig(Config config, string fileName, List<ServerTestItem> selecteds, ECoreType coreType, out string msg)
|
||||||
{
|
{
|
||||||
var coreConfigV2ray = new CoreConfigV2ray(config);
|
if (coreType == ECoreType.sing_box)
|
||||||
return coreConfigV2ray.GenerateClientSpeedtestConfigString(selecteds, out msg);
|
{
|
||||||
|
if (new CoreConfigSingbox(config).GenerateClientSpeedtestConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
JsonUtils.ToFile(singboxConfig, fileName, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (new CoreConfigV2ray(config).GenerateClientSpeedtestConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
JsonUtils.ToFile(v2rayConfig, fileName, false);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.CheckServerSettings;
|
||||||
|
if (coreType == ECoreType.sing_box)
|
||||||
|
{
|
||||||
|
if (new CoreConfigSingbox(config).GenerateClientMultipleLoadConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
JsonUtils.ToFile(singboxConfig, fileName, false);
|
||||||
|
}
|
||||||
|
else if (coreType == ECoreType.Xray)
|
||||||
|
{
|
||||||
|
if (new CoreConfigV2ray(config).GenerateClientMultipleLoadConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
JsonUtils.ToFile(v2rayConfig, fileName, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1383
v2rayN/ServiceLib/Handler/CoreConfig/CoreConfigSingbox.cs
Normal file
1383
v2rayN/ServiceLib/Handler/CoreConfig/CoreConfigSingbox.cs
Normal file
File diff suppressed because it is too large
Load Diff
1250
v2rayN/ServiceLib/Handler/CoreConfig/CoreConfigV2ray.cs
Normal file
1250
v2rayN/ServiceLib/Handler/CoreConfig/CoreConfigV2ray.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,12 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
|
||||||
using System.Reactive.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using v2rayN.Mode;
|
|
||||||
using v2rayN.Resx;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Core process processing class
|
/// Core process processing class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class CoreHandler
|
public class CoreHandler
|
||||||
{
|
{
|
||||||
private Config _config;
|
private Config _config;
|
||||||
private Process? _process;
|
private Process? _process;
|
||||||
@@ -26,19 +22,19 @@ namespace v2rayN.Handler
|
|||||||
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadCore()
|
public void LoadCore(ProfileItem? node)
|
||||||
{
|
{
|
||||||
var node = ConfigHandler.GetDefaultServer(ref _config);
|
|
||||||
if (node == null)
|
if (node == null)
|
||||||
{
|
{
|
||||||
ShowMsg(false, ResUI.CheckServerSettings);
|
ShowMsg(false, ResUI.CheckServerSettings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string fileName = Utils.GetConfigPath(Global.coreConfigFileName);
|
string fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
|
||||||
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);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -48,37 +44,38 @@ namespace v2rayN.Handler
|
|||||||
CoreStart(node);
|
CoreStart(node);
|
||||||
|
|
||||||
//In tun mode, do a delay check and restart the core
|
//In tun mode, do a delay check and restart the core
|
||||||
if (_config.tunModeItem.enableTun)
|
//if (_config.tunModeItem.enableTun)
|
||||||
{
|
//{
|
||||||
Observable.Range(1, 1)
|
// Observable.Range(1, 1)
|
||||||
.Delay(TimeSpan.FromSeconds(15))
|
// .Delay(TimeSpan.FromSeconds(15))
|
||||||
.Subscribe(x =>
|
// .Subscribe(x =>
|
||||||
{
|
// {
|
||||||
{
|
// {
|
||||||
if (_process == null || _process.HasExited)
|
// if (_process == null || _process.HasExited)
|
||||||
{
|
// {
|
||||||
CoreStart(node);
|
// CoreStart(node);
|
||||||
ShowMsg(false, "Tun mode restart the core once");
|
// ShowMsg(false, "Tun mode restart the core once");
|
||||||
Utils.SaveLog("Tun mode restart the core once");
|
// Logging.SaveLog("Tun mode restart the core once");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int LoadCoreConfigString(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;
|
||||||
}
|
}
|
||||||
@@ -106,8 +103,8 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
if (!hasProc)
|
if (!hasProc)
|
||||||
{
|
{
|
||||||
var coreInfos = LazyConfig.Instance.GetCoreInfos();
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
||||||
foreach (var it in coreInfos)
|
foreach (var it in coreInfo)
|
||||||
{
|
{
|
||||||
if (it.coreType == ECoreType.v2rayN)
|
if (it.coreType == ECoreType.v2rayN)
|
||||||
{
|
{
|
||||||
@@ -115,11 +112,11 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
foreach (string vName in it.coreExes)
|
foreach (string vName in it.coreExes)
|
||||||
{
|
{
|
||||||
Process[] existing = Process.GetProcessesByName(vName);
|
var existing = Process.GetProcessesByName(vName);
|
||||||
foreach (Process p in existing)
|
foreach (Process p in existing)
|
||||||
{
|
{
|
||||||
string? path = p.MainModule?.FileName;
|
string? path = p.MainModule?.FileName;
|
||||||
if (path == $"{Utils.GetBinPath(vName, it.coreType)}.exe")
|
if (path == Utils.GetExeName(Utils.GetBinPath(vName, it.coreType.ToString())))
|
||||||
{
|
{
|
||||||
KillProcess(p);
|
KillProcess(p);
|
||||||
}
|
}
|
||||||
@@ -130,7 +127,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,22 +135,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 = Utils.GetExeName(name);
|
||||||
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;
|
||||||
@@ -162,8 +161,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;
|
||||||
@@ -171,44 +170,65 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
private void CoreStart(ProfileItem node)
|
private void CoreStart(ProfileItem node)
|
||||||
{
|
{
|
||||||
|
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||||
|
|
||||||
ECoreType coreType;
|
//ECoreType coreType;
|
||||||
if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
|
//if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
|
||||||
{
|
//{
|
||||||
coreType = ECoreType.sing_box;
|
// coreType = ECoreType.sing_box;
|
||||||
}
|
//}
|
||||||
else
|
//else
|
||||||
{
|
//{
|
||||||
coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
// coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
||||||
}
|
//}
|
||||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(coreType);
|
var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
|
||||||
|
_config.runningCoreType = coreType;
|
||||||
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
||||||
|
|
||||||
var displayLog = node.configType != EConfigType.Custom || node.displayLog;
|
var displayLog = node.configType != EConfigType.Custom || node.displayLog;
|
||||||
var proc = RunProcess(node, coreInfo, "", displayLog, ShowMsg);
|
var proc = RunProcess(node, coreInfo, "", displayLog);
|
||||||
if (proc is null)
|
if (proc is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_process = proc;
|
_process = proc;
|
||||||
|
|
||||||
//start a socks service
|
//start a pre service
|
||||||
if (_process != null && !_process.HasExited)
|
if (_process != null && !_process.HasExited)
|
||||||
{
|
{
|
||||||
if ((node.configType == EConfigType.Custom && node.preSocksPort > 0))
|
ProfileItem? itemSocks = null;
|
||||||
|
var preCoreType = ECoreType.sing_box;
|
||||||
|
if (node.configType != EConfigType.Custom && coreType != ECoreType.sing_box && _config.tunModeItem.enableTun)
|
||||||
{
|
{
|
||||||
var itemSocks = new ProfileItem()
|
itemSocks = new ProfileItem()
|
||||||
{
|
{
|
||||||
coreType = ECoreType.sing_box,
|
coreType = preCoreType,
|
||||||
configType = EConfigType.Socks,
|
configType = EConfigType.Socks,
|
||||||
address = Global.Loopback,
|
address = Global.Loopback,
|
||||||
port = node.preSocksPort
|
sni = node.address, //Tun2SocksAddress
|
||||||
|
port = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks)
|
||||||
};
|
};
|
||||||
string fileName2 = Utils.GetConfigPath(Global.corePreConfigFileName);
|
}
|
||||||
|
else if ((node.configType == EConfigType.Custom && node.preSocksPort > 0))
|
||||||
|
{
|
||||||
|
preCoreType = _config.tunModeItem.enableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
|
itemSocks = new ProfileItem()
|
||||||
|
{
|
||||||
|
coreType = preCoreType,
|
||||||
|
configType = EConfigType.Socks,
|
||||||
|
address = Global.Loopback,
|
||||||
|
port = node.preSocksPort.Value,
|
||||||
|
};
|
||||||
|
_config.runningCoreType = preCoreType;
|
||||||
|
}
|
||||||
|
if (itemSocks != null)
|
||||||
|
{
|
||||||
|
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
|
||||||
if (CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2, out string msg2, out string configStr) == 0)
|
if (CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2, out string msg2, out string configStr) == 0)
|
||||||
{
|
{
|
||||||
var coreInfo2 = LazyConfig.Instance.GetCoreInfo(ECoreType.sing_box);
|
var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
|
||||||
var proc2 = RunProcess(node, coreInfo2, $" -c {Global.corePreConfigFileName}", true, ShowMsg);
|
var proc2 = RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true);
|
||||||
if (proc2 is not null)
|
if (proc2 is not null)
|
||||||
{
|
{
|
||||||
_processPre = proc2;
|
_processPre = proc2;
|
||||||
@@ -218,91 +238,52 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CoreStartViaString(string configStr)
|
private int CoreStartSpeedtest(string configPath, ECoreType coreType)
|
||||||
{
|
{
|
||||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||||
|
|
||||||
|
ShowMsg(false, configPath);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(ECoreType.Xray);
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
||||||
string fileName = CoreFindexe(coreInfo);
|
var proc = RunProcess(new(), coreInfo, $" -c {Global.CoreSpeedtestConfigFileName}", true);
|
||||||
if (fileName == "") return -1;
|
if (proc is null)
|
||||||
|
|
||||||
Process p = new()
|
|
||||||
{
|
{
|
||||||
StartInfo = new ProcessStartInfo
|
return -1;
|
||||||
{
|
|
||||||
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 proc.Id;
|
||||||
return p.Id;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
string msg = ex.Message;
|
string msg = ex.Message;
|
||||||
ShowMsg(false, msg);
|
ShowMsg(false, msg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowMsg(bool updateToTrayTooltip, string msg)
|
private void ShowMsg(bool notify, string msg)
|
||||||
{
|
{
|
||||||
_updateFunc(updateToTrayTooltip, msg);
|
_updateFunc(notify, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion Private
|
||||||
|
|
||||||
#region Process
|
#region Process
|
||||||
|
|
||||||
private Process? RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog, Action<bool, string> update)
|
private Process? RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string fileName = CoreFindexe(coreInfo);
|
string fileName = CoreFindExe(coreInfo);
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
if (Utils.IsNullOrEmpty(fileName))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Process proc = new()
|
Process proc = new()
|
||||||
{
|
{
|
||||||
StartInfo = new ProcessStartInfo
|
StartInfo = new()
|
||||||
{
|
{
|
||||||
FileName = fileName,
|
FileName = fileName,
|
||||||
Arguments = string.Format(coreInfo.arguments, configPath),
|
Arguments = string.Format(coreInfo.arguments, configPath),
|
||||||
@@ -315,22 +296,29 @@ namespace v2rayN.Handler
|
|||||||
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
|
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
var startUpErrorMessage = new StringBuilder();
|
||||||
|
var startUpSuccessful = false;
|
||||||
if (displayLog)
|
if (displayLog)
|
||||||
{
|
{
|
||||||
proc.OutputDataReceived += (sender, e) =>
|
proc.OutputDataReceived += (sender, e) =>
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(e.Data))
|
if (!Utils.IsNullOrEmpty(e.Data))
|
||||||
{
|
{
|
||||||
string msg = e.Data + Environment.NewLine;
|
string msg = e.Data + Environment.NewLine;
|
||||||
update(false, msg);
|
ShowMsg(false, msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
proc.ErrorDataReceived += (sender, e) =>
|
proc.ErrorDataReceived += (sender, e) =>
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(e.Data))
|
if (!Utils.IsNullOrEmpty(e.Data))
|
||||||
{
|
{
|
||||||
string msg = e.Data + Environment.NewLine;
|
string msg = e.Data + Environment.NewLine;
|
||||||
update(false, msg);
|
ShowMsg(false, msg);
|
||||||
|
|
||||||
|
if (!startUpSuccessful)
|
||||||
|
{
|
||||||
|
startUpErrorMessage.Append(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -343,36 +331,45 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
if (proc.WaitForExit(1000))
|
if (proc.WaitForExit(1000))
|
||||||
{
|
{
|
||||||
throw new Exception(displayLog ? proc.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(proc.Handle);
|
LazyConfig.Instance.AddProcess(proc.Handle);
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
string msg = ex.Message;
|
string msg = ex.Message;
|
||||||
update(true, msg);
|
ShowMsg(true, msg);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void KillProcess(Process p)
|
private void KillProcess(Process? proc)
|
||||||
{
|
{
|
||||||
|
if (proc is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
p.CloseMainWindow();
|
proc.Kill();
|
||||||
p.WaitForExit(100);
|
proc.WaitForExit(100);
|
||||||
if (!p.HasExited)
|
if (!proc.HasExited)
|
||||||
{
|
{
|
||||||
p.Kill();
|
proc.Kill();
|
||||||
p.WaitForExit(100);
|
proc.WaitForExit(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
217
v2rayN/ServiceLib/Handler/CoreInfoHandler.cs
Normal file
217
v2rayN/ServiceLib/Handler/CoreInfoHandler.cs
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
using System.Runtime.Intrinsics.X86;
|
||||||
|
|
||||||
|
namespace ServiceLib.Handler
|
||||||
|
{
|
||||||
|
public sealed class CoreInfoHandler
|
||||||
|
{
|
||||||
|
private static readonly Lazy<CoreInfoHandler> _instance = new(() => new());
|
||||||
|
private List<CoreInfo>? _coreInfo;
|
||||||
|
public static CoreInfoHandler Instance => _instance.Value;
|
||||||
|
|
||||||
|
public CoreInfoHandler()
|
||||||
|
{
|
||||||
|
InitCoreInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoreInfo? GetCoreInfo(ECoreType coreType)
|
||||||
|
{
|
||||||
|
if (_coreInfo == null)
|
||||||
|
{
|
||||||
|
InitCoreInfo();
|
||||||
|
}
|
||||||
|
return _coreInfo?.FirstOrDefault(t => t.coreType == coreType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<CoreInfo> GetCoreInfo()
|
||||||
|
{
|
||||||
|
if (_coreInfo == null)
|
||||||
|
{
|
||||||
|
InitCoreInfo();
|
||||||
|
}
|
||||||
|
return _coreInfo ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitCoreInfo()
|
||||||
|
{
|
||||||
|
_coreInfo = [];
|
||||||
|
|
||||||
|
_coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.v2rayN,
|
||||||
|
coreUrl = Global.NUrl,
|
||||||
|
coreReleaseApiUrl = Global.NUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN-32.zip",
|
||||||
|
coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip",
|
||||||
|
coreDownloadUrlArm64 = Global.NUrl + "/download/{0}/v2rayN-arm64.zip",
|
||||||
|
coreDownloadUrlLinux32 = Global.NUrl + "/download/{0}/v2rayN-linux-32.zip",
|
||||||
|
coreDownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip",
|
||||||
|
coreDownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip",
|
||||||
|
});
|
||||||
|
|
||||||
|
_coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.v2fly,
|
||||||
|
coreExes = new List<string> { "wv2ray", "v2ray" },
|
||||||
|
arguments = "",
|
||||||
|
coreUrl = Global.V2flyCoreUrl,
|
||||||
|
coreReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
match = "V2Ray",
|
||||||
|
versionArg = "-version",
|
||||||
|
redirectInfo = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
_coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.SagerNet,
|
||||||
|
coreExes = new List<string> { "SagerNet", "v2ray" },
|
||||||
|
arguments = "run",
|
||||||
|
coreUrl = Global.SagerNetCoreUrl,
|
||||||
|
coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
match = "V2Ray",
|
||||||
|
versionArg = "version",
|
||||||
|
redirectInfo = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
_coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.v2fly_v5,
|
||||||
|
coreExes = new List<string> { "v2ray" },
|
||||||
|
arguments = "run -c config.json -format jsonv5",
|
||||||
|
coreUrl = Global.V2flyCoreUrl,
|
||||||
|
coreReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
match = "V2Ray",
|
||||||
|
versionArg = "version",
|
||||||
|
redirectInfo = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
_coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.Xray,
|
||||||
|
coreExes = new List<string> { "xray", "wxray" },
|
||||||
|
arguments = "run {0}",
|
||||||
|
coreUrl = Global.XrayCoreUrl,
|
||||||
|
coreReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
coreDownloadUrl32 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-32.zip",
|
||||||
|
coreDownloadUrl64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
|
||||||
|
coreDownloadUrlArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
|
||||||
|
coreDownloadUrlLinux32 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-32.zip",
|
||||||
|
coreDownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip",
|
||||||
|
coreDownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip",
|
||||||
|
match = "Xray",
|
||||||
|
versionArg = "-version",
|
||||||
|
redirectInfo = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
_coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.clash,
|
||||||
|
coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" },
|
||||||
|
arguments = "-f config.json" + PortableMode(),
|
||||||
|
coreUrl = Global.ClashCoreUrl,
|
||||||
|
coreReleaseApiUrl = Global.ClashCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
match = "v",
|
||||||
|
versionArg = "-v",
|
||||||
|
redirectInfo = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
_coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.clash_meta,
|
||||||
|
coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" },
|
||||||
|
arguments = "-f config.json" + PortableMode(),
|
||||||
|
coreUrl = Global.ClashMetaCoreUrl,
|
||||||
|
coreReleaseApiUrl = Global.ClashMetaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
match = "v",
|
||||||
|
versionArg = "-v",
|
||||||
|
redirectInfo = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
_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" + PortableMode(),
|
||||||
|
coreUrl = Global.MihomoCoreUrl,
|
||||||
|
coreReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
coreDownloadUrl32 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-windows-386-{0}.zip",
|
||||||
|
coreDownloadUrl64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip",
|
||||||
|
coreDownloadUrlArm64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip",
|
||||||
|
coreDownloadUrlLinux32 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-linux-386-{0}.gz",
|
||||||
|
coreDownloadUrlLinux64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
|
||||||
|
coreDownloadUrlLinuxArm64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz",
|
||||||
|
match = "Mihomo",
|
||||||
|
versionArg = "-v",
|
||||||
|
redirectInfo = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
_coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.hysteria,
|
||||||
|
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
|
||||||
|
arguments = "",
|
||||||
|
coreUrl = Global.HysteriaCoreUrl,
|
||||||
|
coreReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
redirectInfo = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
_coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.naiveproxy,
|
||||||
|
coreExes = new List<string> { "naiveproxy", "naive" },
|
||||||
|
arguments = "config.json",
|
||||||
|
coreUrl = Global.NaiveproxyCoreUrl,
|
||||||
|
redirectInfo = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
_coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.tuic,
|
||||||
|
coreExes = new List<string> { "tuic-client", "tuic" },
|
||||||
|
arguments = "-c config.json",
|
||||||
|
coreUrl = Global.TuicCoreUrl,
|
||||||
|
redirectInfo = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
_coreInfo.Add(new CoreInfo
|
||||||
|
{
|
||||||
|
coreType = ECoreType.sing_box,
|
||||||
|
coreExes = new List<string> { "sing-box-client", "sing-box" },
|
||||||
|
arguments = "run {0} --disable-color",
|
||||||
|
coreUrl = Global.SingboxCoreUrl,
|
||||||
|
redirectInfo = true,
|
||||||
|
coreReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
coreDownloadUrl32 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-386.zip",
|
||||||
|
coreDownloadUrl64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip",
|
||||||
|
coreDownloadUrlArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
|
||||||
|
coreDownloadUrlLinux32 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-386.tar.gz",
|
||||||
|
coreDownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
|
||||||
|
coreDownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
|
||||||
|
match = "sing-box",
|
||||||
|
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),
|
||||||
|
redirectInfo = true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private string PortableMode()
|
||||||
|
{
|
||||||
|
return $" -d \"{Utils.GetBinPath("")}\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,14 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
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.Resx;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///Download
|
///Download
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class DownloadHandle
|
public class DownloadHandler
|
||||||
{
|
{
|
||||||
public event EventHandler<ResultEventArgs>? UpdateCompleted;
|
public event EventHandler<ResultEventArgs>? UpdateCompleted;
|
||||||
|
|
||||||
@@ -34,7 +30,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
|
Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
|
||||||
|
|
||||||
var progress = new Progress<string>();
|
var progress = new Progress<string>();
|
||||||
progress.ProgressChanged += (sender, value) =>
|
progress.ProgressChanged += (sender, value) =>
|
||||||
@@ -62,11 +58,11 @@ namespace v2rayN.Handler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DownloadFileAsync(string url, bool blProxy, int downloadTimeout)
|
public async Task DownloadFileAsync(string url, string fileName, bool blProxy, int downloadTimeout)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
|
Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
|
||||||
UpdateCompleted?.Invoke(this, new ResultEventArgs(false, $"{ResUI.Downloading} {url}"));
|
UpdateCompleted?.Invoke(this, new ResultEventArgs(false, $"{ResUI.Downloading} {url}"));
|
||||||
|
|
||||||
var progress = new Progress<double>();
|
var progress = new Progress<double>();
|
||||||
@@ -78,13 +74,13 @@ namespace v2rayN.Handler
|
|||||||
var webProxy = GetWebProxy(blProxy);
|
var webProxy = GetWebProxy(blProxy);
|
||||||
await DownloaderHelper.Instance.DownloadFileAsync(webProxy,
|
await DownloaderHelper.Instance.DownloadFileAsync(webProxy,
|
||||||
url,
|
url,
|
||||||
Utils.GetTempPath(Utils.GetDownloadFileName(url)),
|
fileName,
|
||||||
progress,
|
progress,
|
||||||
downloadTimeout);
|
downloadTimeout);
|
||||||
}
|
}
|
||||||
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)
|
||||||
@@ -96,7 +92,7 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
public async Task<string?> UrlRedirectAsync(string url, bool blProxy)
|
public async Task<string?> UrlRedirectAsync(string url, bool blProxy)
|
||||||
{
|
{
|
||||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
|
Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
|
||||||
var webRequestHandler = new SocketsHttpHandler
|
var webRequestHandler = new SocketsHttpHandler
|
||||||
{
|
{
|
||||||
AllowAutoRedirect = false,
|
AllowAutoRedirect = false,
|
||||||
@@ -111,7 +107,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Utils.SaveLog("StatusCode error: " + url);
|
Logging.SaveLog("StatusCode error: " + url);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,7 +124,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 +142,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 +162,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)
|
||||||
{
|
{
|
||||||
@@ -185,7 +181,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
|
Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
|
||||||
var webProxy = GetWebProxy(blProxy);
|
var webProxy = GetWebProxy(blProxy);
|
||||||
var client = new HttpClient(new SocketsHttpHandler()
|
var client = new HttpClient(new SocketsHttpHandler()
|
||||||
{
|
{
|
||||||
@@ -212,7 +208,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)
|
||||||
{
|
{
|
||||||
@@ -230,7 +226,7 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
|
Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
|
||||||
|
|
||||||
var webProxy = GetWebProxy(blProxy);
|
var webProxy = GetWebProxy(blProxy);
|
||||||
|
|
||||||
@@ -243,7 +239,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)
|
||||||
{
|
{
|
||||||
@@ -264,19 +260,19 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var config = LazyConfig.Instance.GetConfig();
|
var config = LazyConfig.Instance.Config;
|
||||||
int responseTime = await GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10);
|
int responseTime = await GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10);
|
||||||
return responseTime;
|
return responseTime;
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,8 +282,6 @@ namespace v2rayN.Handler
|
|||||||
int responseTime = -1;
|
int responseTime = -1;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Stopwatch timer = Stopwatch.StartNew();
|
|
||||||
|
|
||||||
using var cts = new CancellationTokenSource();
|
using var cts = new CancellationTokenSource();
|
||||||
cts.CancelAfter(TimeSpan.FromSeconds(downloadTimeout));
|
cts.CancelAfter(TimeSpan.FromSeconds(downloadTimeout));
|
||||||
using var client = new HttpClient(new SocketsHttpHandler()
|
using var client = new HttpClient(new SocketsHttpHandler()
|
||||||
@@ -295,13 +289,21 @@ namespace v2rayN.Handler
|
|||||||
Proxy = webProxy,
|
Proxy = webProxy,
|
||||||
UseProxy = webProxy != null
|
UseProxy = webProxy != null
|
||||||
});
|
});
|
||||||
await client.GetAsync(url, cts.Token);
|
|
||||||
|
|
||||||
responseTime = timer.Elapsed.Milliseconds;
|
List<int> oneTime = [];
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
var timer = Stopwatch.StartNew();
|
||||||
|
await client.GetAsync(url, cts.Token);
|
||||||
|
timer.Stop();
|
||||||
|
oneTime.Add((int)timer.Elapsed.TotalMilliseconds);
|
||||||
|
await Task.Delay(100);
|
||||||
|
}
|
||||||
|
responseTime = oneTime.Where(x => x > 0).OrderBy(x => x).FirstOrDefault();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch //(Exception ex)
|
||||||
{
|
{
|
||||||
//Utils.SaveLog(ex.Message, ex);
|
//Utile.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
return responseTime;
|
return responseTime;
|
||||||
}
|
}
|
||||||
@@ -312,7 +314,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;
|
||||||
205
v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs
Normal file
205
v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
using System.Collections.Specialized;
|
||||||
|
|
||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class BaseFmt
|
||||||
|
{
|
||||||
|
protected static string GetIpv6(string address)
|
||||||
|
{
|
||||||
|
if (Utils.IsIpv6(address))
|
||||||
|
{
|
||||||
|
// 检查地址是否已经被方括号包围,如果没有,则添加方括号
|
||||||
|
return address.StartsWith('[') && address.EndsWith(']') ? address : $"[{address}]";
|
||||||
|
}
|
||||||
|
return address; // 如果不是IPv6地址,直接返回原地址
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
||||||
|
{
|
||||||
|
if (!Utils.IsNullOrEmpty(item.flow))
|
||||||
|
{
|
||||||
|
dicQuery.Add("flow", item.flow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Utils.IsNullOrEmpty(item.streamSecurity))
|
||||||
|
{
|
||||||
|
dicQuery.Add("security", item.streamSecurity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (securityDef != null)
|
||||||
|
{
|
||||||
|
dicQuery.Add("security", securityDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.fingerprint))
|
||||||
|
{
|
||||||
|
dicQuery.Add("fp", Utils.UrlEncode(item.fingerprint));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.publicKey))
|
||||||
|
{
|
||||||
|
dicQuery.Add("pbk", Utils.UrlEncode(item.publicKey));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.shortId))
|
||||||
|
{
|
||||||
|
dicQuery.Add("sid", Utils.UrlEncode(item.shortId));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.spiderX))
|
||||||
|
{
|
||||||
|
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
|
||||||
|
}
|
||||||
|
if (item.allowInsecure.Equals("true"))
|
||||||
|
{
|
||||||
|
dicQuery.Add("allowInsecure", "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : nameof(ETransport.tcp));
|
||||||
|
|
||||||
|
switch (item.network)
|
||||||
|
{
|
||||||
|
case nameof(ETransport.tcp):
|
||||||
|
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||||
|
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||||
|
{
|
||||||
|
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.kcp):
|
||||||
|
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||||
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
|
{
|
||||||
|
dicQuery.Add("seed", Utils.UrlEncode(item.path));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.ws):
|
||||||
|
case nameof(ETransport.httpupgrade):
|
||||||
|
case nameof(ETransport.splithttp):
|
||||||
|
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||||
|
{
|
||||||
|
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
|
{
|
||||||
|
dicQuery.Add("path", Utils.UrlEncode(item.path));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.http):
|
||||||
|
case nameof(ETransport.h2):
|
||||||
|
dicQuery["type"] = nameof(ETransport.http);
|
||||||
|
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||||
|
{
|
||||||
|
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
|
{
|
||||||
|
dicQuery.Add("path", Utils.UrlEncode(item.path));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.quic):
|
||||||
|
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||||
|
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost));
|
||||||
|
dicQuery.Add("key", Utils.UrlEncode(item.path));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.grpc):
|
||||||
|
if (!Utils.IsNullOrEmpty(item.path))
|
||||||
|
{
|
||||||
|
dicQuery.Add("authority", Utils.UrlEncode(item.requestHost));
|
||||||
|
dicQuery.Add("serviceName", Utils.UrlEncode(item.path));
|
||||||
|
if (item.headerType is Global.GrpcGunMode or Global.GrpcMultiMode)
|
||||||
|
{
|
||||||
|
dicQuery.Add("mode", Utils.UrlEncode(item.headerType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
|
||||||
|
{
|
||||||
|
item.flow = query["flow"] ?? "";
|
||||||
|
item.streamSecurity = query["security"] ?? "";
|
||||||
|
item.sni = query["sni"] ?? "";
|
||||||
|
item.alpn = Utils.UrlDecode(query["alpn"] ?? "");
|
||||||
|
item.fingerprint = Utils.UrlDecode(query["fp"] ?? "");
|
||||||
|
item.publicKey = Utils.UrlDecode(query["pbk"] ?? "");
|
||||||
|
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
|
||||||
|
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
|
||||||
|
item.allowInsecure = (query["allowInsecure"] ?? "") == "1" ? "true" : "";
|
||||||
|
|
||||||
|
item.network = query["type"] ?? nameof(ETransport.tcp);
|
||||||
|
switch (item.network)
|
||||||
|
{
|
||||||
|
case nameof(ETransport.tcp):
|
||||||
|
item.headerType = query["headerType"] ?? Global.None;
|
||||||
|
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.kcp):
|
||||||
|
item.headerType = query["headerType"] ?? Global.None;
|
||||||
|
item.path = Utils.UrlDecode(query["seed"] ?? "");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.ws):
|
||||||
|
case nameof(ETransport.httpupgrade):
|
||||||
|
case nameof(ETransport.splithttp):
|
||||||
|
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
|
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.http):
|
||||||
|
case nameof(ETransport.h2):
|
||||||
|
item.network = nameof(ETransport.h2);
|
||||||
|
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
|
item.path = Utils.UrlDecode(query["path"] ?? "/");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.quic):
|
||||||
|
item.headerType = query["headerType"] ?? Global.None;
|
||||||
|
item.requestHost = query["quicSecurity"] ?? Global.None;
|
||||||
|
item.path = Utils.UrlDecode(query["key"] ?? "");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.grpc):
|
||||||
|
item.requestHost = Utils.UrlDecode(query["authority"] ?? "");
|
||||||
|
item.path = Utils.UrlDecode(query["serviceName"] ?? "");
|
||||||
|
item.headerType = Utils.UrlDecode(query["mode"] ?? Global.GrpcGunMode);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static bool Contains(string str, params string[] s)
|
||||||
|
{
|
||||||
|
foreach (var item in s)
|
||||||
|
{
|
||||||
|
if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static string WriteAllText(string strData, string ext = "json")
|
||||||
|
{
|
||||||
|
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.{ext}");
|
||||||
|
File.WriteAllText(fileName, strData);
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
v2rayN/ServiceLib/Handler/Fmt/ClashFmt.cs
Normal file
23
v2rayN/ServiceLib/Handler/Fmt/ClashFmt.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class ClashFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
if (Contains(strData, "port", "socks-port", "proxies"))
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(strData, "yaml");
|
||||||
|
|
||||||
|
var profileItem = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.mihomo,
|
||||||
|
address = fileName,
|
||||||
|
remarks = subRemarks ?? "clash_custom"
|
||||||
|
};
|
||||||
|
return profileItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
90
v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs
Normal file
90
v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class FmtHandler
|
||||||
|
{
|
||||||
|
public static string? GetShareUri(ProfileItem item)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = item.configType switch
|
||||||
|
{
|
||||||
|
EConfigType.VMess => VmessFmt.ToUri(item),
|
||||||
|
EConfigType.Shadowsocks => ShadowsocksFmt.ToUri(item),
|
||||||
|
EConfigType.Socks => SocksFmt.ToUri(item),
|
||||||
|
EConfigType.Trojan => TrojanFmt.ToUri(item),
|
||||||
|
EConfigType.VLESS => VLESSFmt.ToUri(item),
|
||||||
|
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
|
||||||
|
EConfigType.Tuic => TuicFmt.ToUri(item),
|
||||||
|
EConfigType.Wireguard => WireguardFmt.ToUri(item),
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveConfig(string config, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string str = config.TrimEx();
|
||||||
|
if (Utils.IsNullOrEmpty(str))
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedReadConfiguration;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.StartsWith(Global.ProtocolShares[EConfigType.VMess]))
|
||||||
|
{
|
||||||
|
return VmessFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Shadowsocks]))
|
||||||
|
{
|
||||||
|
return ShadowsocksFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Socks]))
|
||||||
|
{
|
||||||
|
return SocksFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Trojan]))
|
||||||
|
{
|
||||||
|
return TrojanFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.VLESS]))
|
||||||
|
{
|
||||||
|
return VLESSFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Hysteria2]) || str.StartsWith(Global.Hysteria2ProtocolShare))
|
||||||
|
{
|
||||||
|
return Hysteria2Fmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Tuic]))
|
||||||
|
{
|
||||||
|
return TuicFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Wireguard]))
|
||||||
|
{
|
||||||
|
return WireguardFmt.Resolve(str, out msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg = ResUI.NonvmessOrssProtocol;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
msg = ResUI.Incorrectconfiguration;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
100
v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs
Normal file
100
v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class Hysteria2Fmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Hysteria2
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(str);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
if (Contains(strData, "server", "up", "down", "listen", "<html>", "<body>"))
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(strData);
|
||||||
|
|
||||||
|
var profileItem = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.hysteria,
|
||||||
|
address = fileName,
|
||||||
|
remarks = subRemarks ?? "hysteria_custom"
|
||||||
|
};
|
||||||
|
return profileItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveFull2(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
if (Contains(strData, "server", "auth", "up", "down", "listen"))
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(strData);
|
||||||
|
|
||||||
|
var profileItem = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.hysteria2,
|
||||||
|
address = fileName,
|
||||||
|
remarks = subRemarks ?? "hysteria2_custom"
|
||||||
|
};
|
||||||
|
return profileItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
v2rayN/ServiceLib/Handler/Fmt/NaiveproxyFmt.cs
Normal file
23
v2rayN/ServiceLib/Handler/Fmt/NaiveproxyFmt.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class NaiveproxyFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
if (Contains(strData, "listen", "proxy", "<html>", "<body>"))
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(strData);
|
||||||
|
|
||||||
|
var profileItem = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.naiveproxy,
|
||||||
|
address = fileName,
|
||||||
|
remarks = subRemarks ?? "naiveproxy_custom"
|
||||||
|
};
|
||||||
|
return profileItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
180
v2rayN/ServiceLib/Handler/Fmt/ShadowsocksFmt.cs
Normal file
180
v2rayN/ServiceLib/Handler/Fmt/ShadowsocksFmt.cs
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class ShadowsocksFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
ProfileItem? item;
|
||||||
|
|
||||||
|
item = ResolveSSLegacy(str) ?? ResolveSip002(str);
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (item.address.Length == 0 || item.port == 0 || item.security.Length == 0 || item.id.Length == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.configType = EConfigType.Shadowsocks;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
string url = string.Empty;
|
||||||
|
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
//url = string.Format("{0}:{1}@{2}:{3}",
|
||||||
|
// item.security,
|
||||||
|
// item.id,
|
||||||
|
// item.address,
|
||||||
|
// item.port);
|
||||||
|
//url = Utile.Base64Encode(url);
|
||||||
|
//new Sip002
|
||||||
|
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
||||||
|
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.Shadowsocks]}{url}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
private static readonly Regex DetailsParser = new(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
|
private static ProfileItem? ResolveSSLegacy(string result)
|
||||||
|
{
|
||||||
|
var match = UrlFinder.Match(result);
|
||||||
|
if (!match.Success)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
ProfileItem item = new();
|
||||||
|
var base64 = match.Groups["base64"].Value.TrimEnd('/');
|
||||||
|
var tag = match.Groups["tag"].Value;
|
||||||
|
if (!Utils.IsNullOrEmpty(tag))
|
||||||
|
{
|
||||||
|
item.remarks = Utils.UrlDecode(tag);
|
||||||
|
}
|
||||||
|
Match details;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
details = DetailsParser.Match(Utils.Base64Decode(base64));
|
||||||
|
}
|
||||||
|
catch (FormatException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!details.Success)
|
||||||
|
return null;
|
||||||
|
item.security = details.Groups["method"].Value;
|
||||||
|
item.id = details.Groups["password"].Value;
|
||||||
|
item.address = details.Groups["hostname"].Value;
|
||||||
|
item.port = Utils.ToInt(details.Groups["port"].Value);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProfileItem? ResolveSip002(string result)
|
||||||
|
{
|
||||||
|
Uri parsedUrl;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parsedUrl = new Uri(result);
|
||||||
|
}
|
||||||
|
catch (UriFormatException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||||
|
address = parsedUrl.IdnHost,
|
||||||
|
port = parsedUrl.Port,
|
||||||
|
};
|
||||||
|
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped);
|
||||||
|
//2022-blake3
|
||||||
|
if (rawUserInfo.Contains(':'))
|
||||||
|
{
|
||||||
|
string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
|
||||||
|
if (userInfoParts.Length != 2)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
item.security = userInfoParts[0];
|
||||||
|
item.id = Utils.UrlDecode(userInfoParts[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// parse base64 UserInfo
|
||||||
|
string userInfo = Utils.Base64Decode(rawUserInfo);
|
||||||
|
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
||||||
|
if (userInfoParts.Length != 2)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
item.security = userInfoParts[0];
|
||||||
|
item.id = userInfoParts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
|
||||||
|
if (queryParameters["plugin"] != null)
|
||||||
|
{
|
||||||
|
//obfs-host exists
|
||||||
|
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
|
||||||
|
if (queryParameters["plugin"].Contains("obfs=http") && !Utils.IsNullOrEmpty(obfsHost))
|
||||||
|
{
|
||||||
|
obfsHost = obfsHost?.Replace("obfs-host=", "");
|
||||||
|
item.network = Global.DefaultNetwork;
|
||||||
|
item.headerType = Global.TcpHeaderHttp;
|
||||||
|
item.requestHost = obfsHost ?? "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ProfileItem>? ResolveSip008(string result)
|
||||||
|
{
|
||||||
|
//SsSIP008
|
||||||
|
var lstSsServer = JsonUtils.Deserialize<List<SsServer>>(result);
|
||||||
|
if (lstSsServer?.Count <= 0)
|
||||||
|
{
|
||||||
|
var ssSIP008 = JsonUtils.Deserialize<SsSIP008>(result);
|
||||||
|
if (ssSIP008?.servers?.Count > 0)
|
||||||
|
{
|
||||||
|
lstSsServer = ssSIP008.servers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstSsServer?.Count > 0)
|
||||||
|
{
|
||||||
|
List<ProfileItem> lst = [];
|
||||||
|
foreach (var it in lstSsServer)
|
||||||
|
{
|
||||||
|
var ssItem = new ProfileItem()
|
||||||
|
{
|
||||||
|
remarks = it.remarks,
|
||||||
|
security = it.method,
|
||||||
|
id = it.password,
|
||||||
|
address = it.server,
|
||||||
|
port = Utils.ToInt(it.server_port)
|
||||||
|
};
|
||||||
|
lst.Add(ssItem);
|
||||||
|
}
|
||||||
|
return lst;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
v2rayN/ServiceLib/Handler/Fmt/SingboxFmt.cs
Normal file
55
v2rayN/ServiceLib/Handler/Fmt/SingboxFmt.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class SingboxFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
var configObjects = JsonUtils.Deserialize<Object[]>(strData);
|
||||||
|
if (configObjects != null && configObjects.Length > 0)
|
||||||
|
{
|
||||||
|
List<ProfileItem> lstResult = [];
|
||||||
|
foreach (var configObject in configObjects)
|
||||||
|
{
|
||||||
|
var objectString = JsonUtils.Serialize(configObject);
|
||||||
|
var singboxCon = JsonUtils.Deserialize<SingboxConfig>(objectString);
|
||||||
|
if (singboxCon?.inbounds?.Count > 0
|
||||||
|
&& singboxCon.outbounds?.Count > 0
|
||||||
|
&& singboxCon.route != null)
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(objectString);
|
||||||
|
|
||||||
|
var profileIt = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.sing_box,
|
||||||
|
address = fileName,
|
||||||
|
remarks = subRemarks ?? "singbox_custom",
|
||||||
|
};
|
||||||
|
lstResult.Add(profileIt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lstResult;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
var singboxConfig = JsonUtils.Deserialize<SingboxConfig>(strData);
|
||||||
|
if (singboxConfig?.inbounds?.Count > 0
|
||||||
|
&& singboxConfig.outbounds?.Count > 0
|
||||||
|
&& singboxConfig.route != null)
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(strData);
|
||||||
|
var profileItem = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.sing_box,
|
||||||
|
address = fileName,
|
||||||
|
remarks = subRemarks ?? "singbox_custom"
|
||||||
|
};
|
||||||
|
|
||||||
|
return profileItem;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
127
v2rayN/ServiceLib/Handler/Fmt/SocksFmt.cs
Normal file
127
v2rayN/ServiceLib/Handler/Fmt/SocksFmt.cs
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class SocksFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
ProfileItem? item;
|
||||||
|
|
||||||
|
item = ResolveSocksNew(str) ?? ResolveSocks(str);
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (item.address.Length == 0 || item.port == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.configType = EConfigType.Socks;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
string url = string.Empty;
|
||||||
|
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
//url = string.Format("{0}:{1}@{2}:{3}",
|
||||||
|
// item.security,
|
||||||
|
// item.id,
|
||||||
|
// item.address,
|
||||||
|
// item.port);
|
||||||
|
//url = Utile.Base64Encode(url);
|
||||||
|
//new
|
||||||
|
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
|
||||||
|
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.Socks]}{url}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProfileItem? ResolveSocks(string result)
|
||||||
|
{
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Socks
|
||||||
|
};
|
||||||
|
result = result[Global.ProtocolShares[EConfigType.Socks].Length..];
|
||||||
|
//remark
|
||||||
|
int indexRemark = result.IndexOf("#");
|
||||||
|
if (indexRemark > 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
item.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
result = result[..indexRemark];
|
||||||
|
}
|
||||||
|
//part decode
|
||||||
|
int indexS = result.IndexOf("@");
|
||||||
|
if (indexS > 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = Utils.Base64Decode(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] arr1 = result.Split('@');
|
||||||
|
if (arr1.Length != 2)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
string[] arr21 = arr1[0].Split(':');
|
||||||
|
//string[] arr22 = arr1[1].Split(':');
|
||||||
|
int indexPort = arr1[1].LastIndexOf(":");
|
||||||
|
if (arr21.Length != 2 || indexPort < 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
item.address = arr1[1][..indexPort];
|
||||||
|
item.port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
|
||||||
|
item.security = arr21[0];
|
||||||
|
item.id = arr21[1];
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProfileItem? ResolveSocksNew(string result)
|
||||||
|
{
|
||||||
|
Uri parsedUrl;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parsedUrl = new Uri(result);
|
||||||
|
}
|
||||||
|
catch (UriFormatException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||||
|
address = parsedUrl.IdnHost,
|
||||||
|
port = parsedUrl.Port,
|
||||||
|
};
|
||||||
|
|
||||||
|
// parse base64 UserInfo
|
||||||
|
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.Unescaped);
|
||||||
|
string userInfo = Utils.Base64Decode(rawUserInfo);
|
||||||
|
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
||||||
|
if (userInfoParts.Length == 2)
|
||||||
|
{
|
||||||
|
item.security = userInfoParts[0];
|
||||||
|
item.id = userInfoParts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
v2rayN/ServiceLib/Handler/Fmt/TrojanFmt.cs
Normal file
49
v2rayN/ServiceLib/Handler/Fmt/TrojanFmt.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class TrojanFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Trojan
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(str);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
string url = string.Empty;
|
||||||
|
|
||||||
|
string remark = string.Empty;
|
||||||
|
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||||
|
{
|
||||||
|
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||||
|
}
|
||||||
|
var dicQuery = new Dictionary<string, string>();
|
||||||
|
GetStdTransport(item, null, ref dicQuery);
|
||||||
|
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.Trojan]}{url}{query}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
v2rayN/ServiceLib/Handler/Fmt/TuicFmt.cs
Normal file
64
v2rayN/ServiceLib/Handler/Fmt/TuicFmt.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class TuicFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Tuic
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(str);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
v2rayN/ServiceLib/Handler/Fmt/V2rayFmt.cs
Normal file
56
v2rayN/ServiceLib/Handler/Fmt/V2rayFmt.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class V2rayFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
var configObjects = JsonUtils.Deserialize<Object[]>(strData);
|
||||||
|
if (configObjects != null && configObjects.Length > 0)
|
||||||
|
{
|
||||||
|
List<ProfileItem> lstResult = [];
|
||||||
|
foreach (var configObject in configObjects)
|
||||||
|
{
|
||||||
|
var objectString = JsonUtils.Serialize(configObject);
|
||||||
|
var v2rayCon = JsonUtils.Deserialize<V2rayConfig>(objectString);
|
||||||
|
if (v2rayCon?.inbounds?.Count > 0
|
||||||
|
&& v2rayCon.outbounds?.Count > 0
|
||||||
|
&& v2rayCon.routing != null)
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(objectString);
|
||||||
|
|
||||||
|
var profileIt = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.Xray,
|
||||||
|
address = fileName,
|
||||||
|
remarks = v2rayCon.remarks ?? subRemarks ?? "v2ray_custom",
|
||||||
|
};
|
||||||
|
lstResult.Add(profileIt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lstResult;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
|
{
|
||||||
|
var v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(strData);
|
||||||
|
if (v2rayConfig?.inbounds?.Count > 0
|
||||||
|
&& v2rayConfig.outbounds?.Count > 0
|
||||||
|
&& v2rayConfig.routing != null)
|
||||||
|
{
|
||||||
|
var fileName = WriteAllText(strData);
|
||||||
|
|
||||||
|
var profileItem = new ProfileItem
|
||||||
|
{
|
||||||
|
coreType = ECoreType.Xray,
|
||||||
|
address = fileName,
|
||||||
|
remarks = v2rayConfig.remarks ?? subRemarks ?? "v2ray_custom"
|
||||||
|
};
|
||||||
|
|
||||||
|
return profileItem;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
v2rayN/ServiceLib/Handler/Fmt/VLESSFmt.cs
Normal file
60
v2rayN/ServiceLib/Handler/Fmt/VLESSFmt.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class VLESSFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.VLESS,
|
||||||
|
security = Global.None
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(str);
|
||||||
|
|
||||||
|
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.security = query["encryption"] ?? Global.None;
|
||||||
|
item.streamSecurity = query["security"] ?? "";
|
||||||
|
ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
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.security))
|
||||||
|
{
|
||||||
|
dicQuery.Add("encryption", item.security);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dicQuery.Add("encryption", Global.None);
|
||||||
|
}
|
||||||
|
GetStdTransport(item, Global.None, ref dicQuery);
|
||||||
|
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.VLESS]}{url}{query}{remark}";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
122
v2rayN/ServiceLib/Handler/Fmt/VmessFmt.cs
Normal file
122
v2rayN/ServiceLib/Handler/Fmt/VmessFmt.cs
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class VmessFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
ProfileItem? item;
|
||||||
|
if (str.IndexOf('?') > 0 && str.IndexOf('&') > 0)
|
||||||
|
{
|
||||||
|
item = ResolveStdVmess(str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item = ResolveVmess(str, out msg);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
string url = string.Empty;
|
||||||
|
|
||||||
|
VmessQRCode vmessQRCode = new()
|
||||||
|
{
|
||||||
|
v = item.configVersion,
|
||||||
|
ps = item.remarks.TrimEx(),
|
||||||
|
add = item.address,
|
||||||
|
port = item.port,
|
||||||
|
id = item.id,
|
||||||
|
aid = item.alterId,
|
||||||
|
scy = item.security,
|
||||||
|
net = item.network,
|
||||||
|
type = item.headerType,
|
||||||
|
host = item.requestHost,
|
||||||
|
path = item.path,
|
||||||
|
tls = item.streamSecurity,
|
||||||
|
sni = item.sni,
|
||||||
|
alpn = item.alpn,
|
||||||
|
fp = item.fingerprint
|
||||||
|
};
|
||||||
|
|
||||||
|
url = JsonUtils.Serialize(vmessQRCode);
|
||||||
|
url = Utils.Base64Encode(url);
|
||||||
|
url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}";
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProfileItem? ResolveVmess(string result, out string msg)
|
||||||
|
{
|
||||||
|
msg = string.Empty;
|
||||||
|
var item = new ProfileItem
|
||||||
|
{
|
||||||
|
configType = EConfigType.VMess
|
||||||
|
};
|
||||||
|
|
||||||
|
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
||||||
|
result = Utils.Base64Decode(result);
|
||||||
|
|
||||||
|
//转成Json
|
||||||
|
VmessQRCode? vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
|
||||||
|
if (vmessQRCode == null)
|
||||||
|
{
|
||||||
|
msg = ResUI.FailedConversionConfiguration;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.network = Global.DefaultNetwork;
|
||||||
|
item.headerType = Global.None;
|
||||||
|
|
||||||
|
item.configVersion = Utils.ToInt(vmessQRCode.v);
|
||||||
|
item.remarks = Utils.ToString(vmessQRCode.ps);
|
||||||
|
item.address = Utils.ToString(vmessQRCode.add);
|
||||||
|
item.port = Utils.ToInt(vmessQRCode.port);
|
||||||
|
item.id = Utils.ToString(vmessQRCode.id);
|
||||||
|
item.alterId = Utils.ToInt(vmessQRCode.aid);
|
||||||
|
item.security = Utils.ToString(vmessQRCode.scy);
|
||||||
|
|
||||||
|
item.security = !Utils.IsNullOrEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
|
||||||
|
if (!Utils.IsNullOrEmpty(vmessQRCode.net))
|
||||||
|
{
|
||||||
|
item.network = vmessQRCode.net;
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(vmessQRCode.type))
|
||||||
|
{
|
||||||
|
item.headerType = vmessQRCode.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.requestHost = Utils.ToString(vmessQRCode.host);
|
||||||
|
item.path = Utils.ToString(vmessQRCode.path);
|
||||||
|
item.streamSecurity = Utils.ToString(vmessQRCode.tls);
|
||||||
|
item.sni = Utils.ToString(vmessQRCode.sni);
|
||||||
|
item.alpn = Utils.ToString(vmessQRCode.alpn);
|
||||||
|
item.fingerprint = Utils.ToString(vmessQRCode.fp);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileItem? ResolveStdVmess(string str)
|
||||||
|
{
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.VMess,
|
||||||
|
security = "auto"
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(str);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
69
v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs
Normal file
69
v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
namespace ServiceLib.Handler.Fmt
|
||||||
|
{
|
||||||
|
public class WireguardFmt : BaseFmt
|
||||||
|
{
|
||||||
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
|
{
|
||||||
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
|
|
||||||
|
ProfileItem item = new()
|
||||||
|
{
|
||||||
|
configType = EConfigType.Wireguard
|
||||||
|
};
|
||||||
|
|
||||||
|
Uri url = new(str);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? ToUri(ProfileItem? item)
|
||||||
|
{
|
||||||
|
if (item == null) return null;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
242
v2rayN/ServiceLib/Handler/LazyConfig.cs
Normal file
242
v2rayN/ServiceLib/Handler/LazyConfig.cs
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
namespace ServiceLib.Handler
|
||||||
|
{
|
||||||
|
public sealed class LazyConfig
|
||||||
|
{
|
||||||
|
private static readonly Lazy<LazyConfig> _instance = new(() => new());
|
||||||
|
private Config _config;
|
||||||
|
private int? _statePort;
|
||||||
|
private int? _statePort2;
|
||||||
|
|
||||||
|
public static LazyConfig Instance => _instance.Value;
|
||||||
|
public Config Config => _config;
|
||||||
|
|
||||||
|
public int StatePort
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_statePort ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api));
|
||||||
|
return _statePort.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int StatePort2
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
|
||||||
|
return _statePort2.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Job? _processJob;
|
||||||
|
|
||||||
|
public LazyConfig()
|
||||||
|
{
|
||||||
|
SQLiteHelper.Instance.CreateTable<SubItem>();
|
||||||
|
SQLiteHelper.Instance.CreateTable<ProfileItem>();
|
||||||
|
SQLiteHelper.Instance.CreateTable<ServerStatItem>();
|
||||||
|
SQLiteHelper.Instance.CreateTable<RoutingItem>();
|
||||||
|
SQLiteHelper.Instance.CreateTable<ProfileExItem>();
|
||||||
|
SQLiteHelper.Instance.CreateTable<DNSItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Config
|
||||||
|
|
||||||
|
public void SetConfig(Config config) => _config = config;
|
||||||
|
|
||||||
|
public int GetLocalPort(EInboundProtocol protocol)
|
||||||
|
{
|
||||||
|
var localPort = _config.inbound.FirstOrDefault(t => t.protocol == nameof(EInboundProtocol.socks))?.localPort ?? 10808;
|
||||||
|
return localPort + (int)protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddProcess(IntPtr processHandle)
|
||||||
|
{
|
||||||
|
if (Utils.IsWindows())
|
||||||
|
{
|
||||||
|
_processJob ??= new();
|
||||||
|
_processJob?.AddProcess(processHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Config
|
||||||
|
|
||||||
|
#region SqliteHelper
|
||||||
|
|
||||||
|
public List<SubItem> SubItems()
|
||||||
|
{
|
||||||
|
return SQLiteHelper.Instance.Table<SubItem>().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubItem GetSubItem(string subid)
|
||||||
|
{
|
||||||
|
return SQLiteHelper.Instance.Table<SubItem>().FirstOrDefault(t => t.id == subid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ProfileItem> ProfileItems(string subid)
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(subid))
|
||||||
|
{
|
||||||
|
return SQLiteHelper.Instance.Table<ProfileItem>().ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return SQLiteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> ProfileItemIndexes(string subid)
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(subid))
|
||||||
|
{
|
||||||
|
return SQLiteHelper.Instance.Table<ProfileItem>().Select(t => t.indexId).ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return SQLiteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).Select(t => t.indexId).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ProfileItemModel> ProfileItems(string subid, string filter)
|
||||||
|
{
|
||||||
|
var sql = @$"select a.*
|
||||||
|
,b.remarks subRemarks
|
||||||
|
from ProfileItem a
|
||||||
|
left join SubItem b on a.subid = b.id
|
||||||
|
where 1=1 ";
|
||||||
|
if (!Utils.IsNullOrEmpty(subid))
|
||||||
|
{
|
||||||
|
sql += $" and a.subid = '{subid}'";
|
||||||
|
}
|
||||||
|
if (!Utils.IsNullOrEmpty(filter))
|
||||||
|
{
|
||||||
|
if (filter.Contains('\''))
|
||||||
|
{
|
||||||
|
filter = filter.Replace("'", "");
|
||||||
|
}
|
||||||
|
sql += String.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SQLiteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ProfileItemModel> ProfileItemsEx(string subid, string filter)
|
||||||
|
{
|
||||||
|
var lstModel = ProfileItems(_config.subIndexId, filter);
|
||||||
|
|
||||||
|
ConfigHandler.SetDefaultServer(_config, lstModel);
|
||||||
|
|
||||||
|
var lstServerStat = (_config.guiItem.enableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
|
||||||
|
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
|
||||||
|
lstModel = (from t in lstModel
|
||||||
|
join t2 in lstServerStat on t.indexId equals t2.indexId into t2b
|
||||||
|
from t22 in t2b.DefaultIfEmpty()
|
||||||
|
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
|
||||||
|
from t33 in t3b.DefaultIfEmpty()
|
||||||
|
select new ProfileItemModel
|
||||||
|
{
|
||||||
|
indexId = t.indexId,
|
||||||
|
configType = t.configType,
|
||||||
|
remarks = t.remarks,
|
||||||
|
address = t.address,
|
||||||
|
port = t.port,
|
||||||
|
security = t.security,
|
||||||
|
network = t.network,
|
||||||
|
streamSecurity = t.streamSecurity,
|
||||||
|
subid = t.subid,
|
||||||
|
subRemarks = t.subRemarks,
|
||||||
|
isActive = t.indexId == _config.indexId,
|
||||||
|
sort = t33 == null ? 0 : t33.sort,
|
||||||
|
delay = t33 == null ? 0 : t33.delay,
|
||||||
|
delayVal = t33?.delay != 0 ? $"{t33?.delay} {Global.DelayUnit}" : string.Empty,
|
||||||
|
speedVal = t33?.speed != 0 ? $"{t33?.speed} {Global.SpeedUnit}" : string.Empty,
|
||||||
|
todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown),
|
||||||
|
todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp),
|
||||||
|
totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown),
|
||||||
|
totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp)
|
||||||
|
}).OrderBy(t => t.sort).ToList();
|
||||||
|
|
||||||
|
return lstModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProfileItem? GetProfileItem(string indexId)
|
||||||
|
{
|
||||||
|
if (Utils.IsNullOrEmpty(indexId))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
return SQLiteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).OrderBy(t => t.sort).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoutingItem GetRoutingItem(string id)
|
||||||
|
{
|
||||||
|
return SQLiteHelper.Instance.Table<RoutingItem>().FirstOrDefault(it => it.locked == false && it.id == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
public List<string> GetShadowsocksSecurities(ProfileItem profileItem)
|
||||||
|
{
|
||||||
|
var coreType = GetCoreType(profileItem, EConfigType.Shadowsocks);
|
||||||
|
switch (coreType)
|
||||||
|
{
|
||||||
|
case ECoreType.v2fly:
|
||||||
|
return Global.SsSecurities;
|
||||||
|
|
||||||
|
case ECoreType.Xray:
|
||||||
|
return Global.SsSecuritiesInXray;
|
||||||
|
|
||||||
|
case ECoreType.sing_box:
|
||||||
|
return Global.SsSecuritiesInSingbox;
|
||||||
|
}
|
||||||
|
return Global.SsSecuritiesInSagerNet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
|
||||||
|
{
|
||||||
|
if (profileItem?.coreType != null)
|
||||||
|
{
|
||||||
|
return (ECoreType)profileItem.coreType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_config.coreTypeItem == null)
|
||||||
|
{
|
||||||
|
return ECoreType.Xray;
|
||||||
|
}
|
||||||
|
var item = _config.coreTypeItem.FirstOrDefault(it => it.configType == eConfigType);
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return ECoreType.Xray;
|
||||||
|
}
|
||||||
|
return item.coreType;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Core Type
|
||||||
|
}
|
||||||
|
}
|
||||||
41
v2rayN/ServiceLib/Handler/NoticeHandler.cs
Normal file
41
v2rayN/ServiceLib/Handler/NoticeHandler.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace ServiceLib.Handler
|
||||||
|
{
|
||||||
|
public class NoticeHandler
|
||||||
|
{
|
||||||
|
public void Enqueue(string? content)
|
||||||
|
{
|
||||||
|
if (content.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MessageBus.Current.SendMessage(content, Global.CommandSendSnackMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendMessage(string? content)
|
||||||
|
{
|
||||||
|
if (content.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MessageBus.Current.SendMessage(content, Global.CommandSendMsgView);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendMessage(string? content, bool time)
|
||||||
|
{
|
||||||
|
if (content.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
content = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} {content}";
|
||||||
|
SendMessage(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 v2rayN.Base;
|
|
||||||
using v2rayN.Mode;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
//using System.Reactive.Linq;
|
||||||
|
|
||||||
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
internal class ProfileExHandler
|
public 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,33 +15,24 @@ namespace v2rayN.Handler
|
|||||||
public ProfileExHandler()
|
public ProfileExHandler()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
}
|
|
||||||
|
|
||||||
private void Init()
|
|
||||||
{
|
|
||||||
SqliteHelper.Instance.Execute($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
|
|
||||||
|
|
||||||
_lstProfileEx = new(SqliteHelper.Instance.Table<ProfileExItem>());
|
|
||||||
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var cnt = _queIndexIds.Count;
|
SaveQueueIndexIds();
|
||||||
for (int i = 0; i < cnt; i++)
|
await Task.Delay(1000 * 600);
|
||||||
{
|
|
||||||
var id = _queIndexIds.Dequeue();
|
|
||||||
var item = _lstProfileEx.FirstOrDefault(t => t.indexId == id);
|
|
||||||
if (item is not null)
|
|
||||||
{
|
|
||||||
SqliteHelper.Instance.Replace(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await Task.Delay(1000 * 60);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Init()
|
||||||
|
{
|
||||||
|
SQLiteHelper.Instance.Execute($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
|
||||||
|
|
||||||
|
_lstProfileEx = new(SQLiteHelper.Instance.Table<ProfileExItem>());
|
||||||
|
}
|
||||||
|
|
||||||
private void IndexIdEnqueue(string indexId)
|
private void IndexIdEnqueue(string indexId)
|
||||||
{
|
{
|
||||||
if (!Utils.IsNullOrEmpty(indexId) && !_queIndexIds.Contains(indexId))
|
if (!Utils.IsNullOrEmpty(indexId) && !_queIndexIds.Contains(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,26 +1,19 @@
|
|||||||
using System.Diagnostics;
|
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.Resx;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
internal class SpeedtestHandler
|
public 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;
|
||||||
private Action<string, string, string> _updateFunc;
|
private Action<SpeedTestResult> _updateFunc;
|
||||||
|
private bool _exitLoop = false;
|
||||||
|
|
||||||
public SpeedtestHandler(Config config)
|
public SpeedtestHandler(Config config, CoreHandler coreHandler, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<SpeedTestResult> update)
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SpeedtestHandler(Config config, CoreHandler coreHandler, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<string, string, string> update)
|
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_coreHandler = coreHandler;
|
_coreHandler = coreHandler;
|
||||||
@@ -30,7 +23,7 @@ namespace v2rayN.Handler
|
|||||||
_selecteds = new List<ServerTestItem>();
|
_selecteds = new List<ServerTestItem>();
|
||||||
foreach (var it in selecteds)
|
foreach (var it in selecteds)
|
||||||
{
|
{
|
||||||
if (it.configType == EConfigType.Custom || it.configType == EConfigType.Hysteria2)
|
if (it.configType == EConfigType.Custom)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -51,7 +44,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 +65,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 +83,51 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunPingSubAsync(Action<ServerTestItem> updateFun)
|
public void ExitLoop()
|
||||||
|
{
|
||||||
|
_exitLoop = true;
|
||||||
|
UpdateFunc("", ResUI.SpeedtestingStop);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
await Task.Delay(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 async void RunPing()
|
|
||||||
{
|
|
||||||
await RunPingSubAsync((ServerTestItem it) =>
|
|
||||||
{
|
|
||||||
long time = Ping(it.address);
|
|
||||||
var output = FormatOut(time, Global.DelayUnit);
|
|
||||||
|
|
||||||
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
|
||||||
UpdateFunc(it.indexId, output);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void RunTcping()
|
|
||||||
{
|
|
||||||
await RunPingSubAsync((ServerTestItem it) =>
|
|
||||||
{
|
{
|
||||||
int time = GetTcpingTime(it.address, it.port);
|
ProfileExHandler.Instance.SaveTo();
|
||||||
var output = FormatOut(time, Global.DelayUnit);
|
}
|
||||||
|
|
||||||
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
|
return Task.CompletedTask;
|
||||||
UpdateFunc(it.indexId, output);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task RunRealPing()
|
private Task RunRealPing()
|
||||||
@@ -150,14 +137,14 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
string msg = string.Empty;
|
string msg = string.Empty;
|
||||||
|
|
||||||
pid = _coreHandler.LoadCoreConfigString(_selecteds);
|
pid = _coreHandler.LoadCoreConfigSpeedtest(_selecteds);
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
UpdateFunc("", ResUI.FailedToRunCore);
|
UpdateFunc("", ResUI.FailedToRunCore);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadHandle downloadHandle = new DownloadHandle();
|
DownloadHandler downloadHandle = new DownloadHandler();
|
||||||
|
|
||||||
List<Task> tasks = new();
|
List<Task> tasks = new();
|
||||||
foreach (var it in _selecteds)
|
foreach (var it in _selecteds)
|
||||||
@@ -184,7 +171,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -192,11 +179,14 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +201,7 @@ namespace v2rayN.Handler
|
|||||||
// _selecteds = _selecteds.OrderBy(t => t.delay).ToList();
|
// _selecteds = _selecteds.OrderBy(t => t.delay).ToList();
|
||||||
//}
|
//}
|
||||||
|
|
||||||
pid = _coreHandler.LoadCoreConfigString(_selecteds);
|
pid = _coreHandler.LoadCoreConfigSpeedtest(_selecteds);
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
UpdateFunc("", ResUI.FailedToRunCore);
|
UpdateFunc("", ResUI.FailedToRunCore);
|
||||||
@@ -221,10 +211,15 @@ namespace v2rayN.Handler
|
|||||||
string url = _config.speedTestItem.speedTestUrl;
|
string url = _config.speedTestItem.speedTestUrl;
|
||||||
var timeout = _config.speedTestItem.speedTestTimeout;
|
var timeout = _config.speedTestItem.speedTestTimeout;
|
||||||
|
|
||||||
DownloadHandle downloadHandle = new();
|
DownloadHandler downloadHandle = new();
|
||||||
|
|
||||||
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;
|
||||||
@@ -268,7 +263,7 @@ namespace v2rayN.Handler
|
|||||||
private async Task RunSpeedTestMulti()
|
private async Task RunSpeedTestMulti()
|
||||||
{
|
{
|
||||||
int pid = -1;
|
int pid = -1;
|
||||||
pid = _coreHandler.LoadCoreConfigString(_selecteds);
|
pid = _coreHandler.LoadCoreConfigSpeedtest(_selecteds);
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
UpdateFunc("", ResUI.FailedToRunCore);
|
UpdateFunc("", ResUI.FailedToRunCore);
|
||||||
@@ -278,10 +273,16 @@ namespace v2rayN.Handler
|
|||||||
string url = _config.speedTestItem.speedTestUrl;
|
string url = _config.speedTestItem.speedTestUrl;
|
||||||
var timeout = _config.speedTestItem.speedTestTimeout;
|
var timeout = _config.speedTestItem.speedTestTimeout;
|
||||||
|
|
||||||
DownloadHandle downloadHandle = new();
|
DownloadHandler downloadHandle = new();
|
||||||
|
|
||||||
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;
|
||||||
@@ -333,10 +334,10 @@ namespace v2rayN.Handler
|
|||||||
await RunSpeedTestMulti();
|
await RunSpeedTestMulti();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> GetRealPingTime(DownloadHandle downloadHandle, IWebProxy webProxy)
|
private async Task<string> GetRealPingTime(DownloadHandler downloadHandle, IWebProxy webProxy)
|
||||||
{
|
{
|
||||||
int responseTime = await downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10);
|
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(responseTime, Global.DelayUnit);
|
return FormatOut(responseTime, Global.DelayUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,70 +347,32 @@ 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];
|
||||||
}
|
}
|
||||||
|
|
||||||
Stopwatch timer = new();
|
var timer = Stopwatch.StartNew();
|
||||||
timer.Start();
|
|
||||||
|
|
||||||
IPEndPoint endPoint = new(ipAddress, port);
|
IPEndPoint endPoint = new(ipAddress, port);
|
||||||
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
|
||||||
IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null);
|
var result = clientSocket.BeginConnect(endPoint, null, null);
|
||||||
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
|
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
|
||||||
throw new TimeoutException("connect timeout (5s): " + url);
|
throw new TimeoutException("connect timeout (5s): " + url);
|
||||||
clientSocket.EndConnect(result);
|
clientSocket.EndConnect(result);
|
||||||
|
|
||||||
timer.Stop();
|
timer.Stop();
|
||||||
responseTime = timer.Elapsed.Milliseconds;
|
responseTime = (int)timer.Elapsed.TotalMilliseconds;
|
||||||
}
|
}
|
||||||
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"))
|
||||||
@@ -421,7 +384,7 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
private void UpdateFunc(string indexId, string delay, string speed = "")
|
private void UpdateFunc(string indexId, string delay, string speed = "")
|
||||||
{
|
{
|
||||||
_updateFunc(indexId, delay, speed);
|
_updateFunc(new() { IndexId = indexId, Delay = delay, Speed = speed });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
using System.Net;
|
namespace ServiceLib.Handler.Statistics
|
||||||
using System.Net.Sockets;
|
|
||||||
using v2rayN.Base;
|
|
||||||
using v2rayN.Mode;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
|
||||||
{
|
{
|
||||||
internal class StatisticsHandler
|
public class StatisticsHandler
|
||||||
{
|
{
|
||||||
|
private static readonly Lazy<StatisticsHandler> instance = new(() => new());
|
||||||
|
public static StatisticsHandler Instance => instance.Value;
|
||||||
|
|
||||||
private Config _config;
|
private Config _config;
|
||||||
private ServerStatItem? _serverStatItem;
|
private ServerStatItem? _serverStatItem;
|
||||||
private List<ServerStatItem> _lstServerStat;
|
private List<ServerStatItem> _lstServerStat;
|
||||||
@@ -15,21 +13,17 @@ namespace v2rayN.Handler
|
|||||||
private StatisticsSingbox? _statisticsSingbox;
|
private StatisticsSingbox? _statisticsSingbox;
|
||||||
|
|
||||||
public List<ServerStatItem> ServerStat => _lstServerStat;
|
public List<ServerStatItem> ServerStat => _lstServerStat;
|
||||||
public bool Enable { get; set; }
|
|
||||||
|
|
||||||
public StatisticsHandler(Config config, Action<ServerSpeedItem> update)
|
public void Init(Config config, Action<ServerSpeedItem> update)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
Enable = config.guiItem.enableStatistics;
|
_updateFunc = update;
|
||||||
if (!Enable)
|
if (!config.guiItem.enableStatistics)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateFunc = update;
|
InitData();
|
||||||
|
|
||||||
Init();
|
|
||||||
Global.statePort = GetFreePort();
|
|
||||||
|
|
||||||
_statisticsV2Ray = new StatisticsV2ray(config, UpdateServerStat);
|
_statisticsV2Ray = new StatisticsV2ray(config, UpdateServerStat);
|
||||||
_statisticsSingbox = new StatisticsSingbox(config, UpdateServerStat);
|
_statisticsSingbox = new StatisticsSingbox(config, UpdateServerStat);
|
||||||
@@ -44,13 +38,13 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
@@ -59,28 +53,35 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SqliteHelper.Instance.UpdateAll(_lstServerStat);
|
if (_lstServerStat != null)
|
||||||
|
{
|
||||||
|
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 InitData()
|
||||||
{
|
{
|
||||||
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)
|
private void UpdateServerStat(ServerSpeedItem server)
|
||||||
{
|
{
|
||||||
GetServerStatItem(_config.indexId);
|
GetServerStatItem(_config.indexId);
|
||||||
|
|
||||||
|
if (_serverStatItem is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (server.proxyUp != 0 || server.proxyDown != 0)
|
if (server.proxyUp != 0 || server.proxyDown != 0)
|
||||||
{
|
{
|
||||||
_serverStatItem.todayUp += server.proxyUp;
|
_serverStatItem.todayUp += server.proxyUp;
|
||||||
@@ -88,15 +89,13 @@ namespace v2rayN.Handler
|
|||||||
_serverStatItem.totalUp += server.proxyUp;
|
_serverStatItem.totalUp += server.proxyUp;
|
||||||
_serverStatItem.totalDown += server.proxyDown;
|
_serverStatItem.totalDown += server.proxyDown;
|
||||||
}
|
}
|
||||||
if (Global.ShowInTaskbar)
|
|
||||||
{
|
server.indexId = _config.indexId;
|
||||||
server.indexId = _config.indexId;
|
server.todayUp = _serverStatItem.todayUp;
|
||||||
server.todayUp = _serverStatItem.todayUp;
|
server.todayDown = _serverStatItem.todayDown;
|
||||||
server.todayDown = _serverStatItem.todayDown;
|
server.totalUp = _serverStatItem.totalUp;
|
||||||
server.totalUp = _serverStatItem.totalUp;
|
server.totalDown = _serverStatItem.totalDown;
|
||||||
server.totalDown = _serverStatItem.totalDown;
|
_updateFunc(server);
|
||||||
_updateFunc(server);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetServerStatItem(string indexId)
|
private void GetServerStatItem(string indexId)
|
||||||
@@ -121,7 +120,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,29 +132,5 @@ namespace v2rayN.Handler
|
|||||||
_serverStatItem.dateNow = ticks;
|
_serverStatItem.dateNow = ticks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetFreePort()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int defaultPort = 9090;
|
|
||||||
if (!Utils.PortInUse(defaultPort))
|
|
||||||
{
|
|
||||||
return defaultPort;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
TcpListener l = new(IPAddress.Loopback, 0);
|
|
||||||
l.Start();
|
|
||||||
int port = ((IPEndPoint)l.LocalEndpoint).Port;
|
|
||||||
l.Stop();
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
return 69090;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using v2rayN.Mode;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace ServiceLib.Handler.Statistics
|
||||||
{
|
{
|
||||||
internal class StatisticsSingbox
|
public class StatisticsSingbox
|
||||||
{
|
{
|
||||||
private Config _config;
|
private Config _config;
|
||||||
private bool _exitFlag;
|
private bool _exitFlag;
|
||||||
@@ -27,7 +26,7 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
url = $"ws://{Global.Loopback}:{Global.statePort}/traffic";
|
url = $"ws://{Global.Loopback}:{LazyConfig.Instance.StatePort2}/traffic";
|
||||||
|
|
||||||
if (webSocket == null)
|
if (webSocket == null)
|
||||||
{
|
{
|
||||||
@@ -51,7 +50,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,8 +60,13 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
while (!_exitFlag)
|
while (!_exitFlag)
|
||||||
{
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (!(_config.IsRunningCore(ECoreType.clash)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (webSocket != null)
|
if (webSocket != null)
|
||||||
{
|
{
|
||||||
if (webSocket.State == WebSocketState.Aborted
|
if (webSocket.State == WebSocketState.Aborted
|
||||||
@@ -84,7 +88,7 @@ namespace v2rayN.Handler
|
|||||||
while (!res.CloseStatus.HasValue)
|
while (!res.CloseStatus.HasValue)
|
||||||
{
|
{
|
||||||
var result = Encoding.UTF8.GetString(buffer, 0, res.Count);
|
var result = Encoding.UTF8.GetString(buffer, 0, res.Count);
|
||||||
if (!string.IsNullOrEmpty(result))
|
if (!Utils.IsNullOrEmpty(result))
|
||||||
{
|
{
|
||||||
ParseOutput(result, out ulong up, out ulong down);
|
ParseOutput(result, out ulong up, out ulong down);
|
||||||
|
|
||||||
@@ -101,10 +105,6 @@ namespace v2rayN.Handler
|
|||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
await Task.Delay(1000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ namespace v2rayN.Handler
|
|||||||
up = 0; down = 0;
|
up = 0; down = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var trafficItem = Utils.FromJson<TrafficItem>(source);
|
var trafficItem = JsonUtils.Deserialize<TrafficItem>(source);
|
||||||
if (trafficItem != null)
|
if (trafficItem != null)
|
||||||
{
|
{
|
||||||
up = trafficItem.up;
|
up = trafficItem.up;
|
||||||
@@ -1,19 +1,18 @@
|
|||||||
using Grpc.Core;
|
using Grpc.Core;
|
||||||
using Grpc.Net.Client;
|
using Grpc.Net.Client;
|
||||||
using ProtosLib.Statistics;
|
using ProtosLib.Statistics;
|
||||||
using v2rayN.Mode;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace ServiceLib.Handler.Statistics
|
||||||
{
|
{
|
||||||
internal class StatisticsV2ray
|
public class StatisticsV2ray
|
||||||
{
|
{
|
||||||
private Mode.Config _config;
|
private Models.Config _config;
|
||||||
private GrpcChannel _channel;
|
private GrpcChannel? _channel;
|
||||||
private StatsService.StatsServiceClient _client;
|
private StatsService.StatsServiceClient? _client;
|
||||||
private bool _exitFlag;
|
private bool _exitFlag;
|
||||||
private Action<ServerSpeedItem> _updateFunc;
|
private Action<ServerSpeedItem> _updateFunc;
|
||||||
|
|
||||||
public StatisticsV2ray(Mode.Config config, Action<ServerSpeedItem> update)
|
public StatisticsV2ray(Models.Config config, Action<ServerSpeedItem> update)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_updateFunc = update;
|
_updateFunc = update;
|
||||||
@@ -26,10 +25,17 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
private void GrpcInit()
|
private void GrpcInit()
|
||||||
{
|
{
|
||||||
if (_channel == null)
|
if (_channel is null)
|
||||||
{
|
{
|
||||||
_channel = GrpcChannel.ForAddress($"{Global.httpProtocol}{Global.Loopback}:{Global.statePort}");
|
try
|
||||||
_client = new StatsService.StatsServiceClient(_channel);
|
{
|
||||||
|
_channel = GrpcChannel.ForAddress($"{Global.HttpProtocol}{Global.Loopback}:{LazyConfig.Instance.StatePort}");
|
||||||
|
_client = new StatsService.StatsServiceClient(_channel);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(ex.Message, ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,14 +48,20 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
while (!_exitFlag)
|
while (!_exitFlag)
|
||||||
{
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_channel.State == ConnectivityState.Ready)
|
if (!(_config.IsRunningCore(ECoreType.Xray)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (_channel?.State == ConnectivityState.Ready)
|
||||||
{
|
{
|
||||||
QueryStatsResponse? res = null;
|
QueryStatsResponse? res = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
res = await _client.QueryStatsAsync(new QueryStatsRequest() { Pattern = "", Reset = true });
|
if (_client != null)
|
||||||
|
res = await _client.QueryStatsAsync(new QueryStatsRequest() { Pattern = "", Reset = true });
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -61,8 +73,8 @@ namespace v2rayN.Handler
|
|||||||
_updateFunc(server);
|
_updateFunc(server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Task.Delay(1000);
|
if (_channel != null)
|
||||||
await _channel.ConnectAsync();
|
await _channel.ConnectAsync();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -73,6 +85,8 @@ namespace v2rayN.Handler
|
|||||||
private void ParseOutput(Google.Protobuf.Collections.RepeatedField<Stat> source, out ServerSpeedItem server)
|
private void ParseOutput(Google.Protobuf.Collections.RepeatedField<Stat> source, out ServerSpeedItem server)
|
||||||
{
|
{
|
||||||
server = new();
|
server = new();
|
||||||
|
long aggregateProxyUp = 0;
|
||||||
|
long aggregateProxyDown = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (Stat stat in source)
|
foreach (Stat stat in source)
|
||||||
@@ -87,18 +101,18 @@ namespace v2rayN.Handler
|
|||||||
name = nStr[1];
|
name = nStr[1];
|
||||||
type = nStr[3];
|
type = nStr[3];
|
||||||
|
|
||||||
if (name == Global.agentTag)
|
if (name.StartsWith(Global.ProxyTag))
|
||||||
{
|
{
|
||||||
if (type == "uplink")
|
if (type == "uplink")
|
||||||
{
|
{
|
||||||
server.proxyUp = value;
|
aggregateProxyUp += value;
|
||||||
}
|
}
|
||||||
else if (type == "downlink")
|
else if (type == "downlink")
|
||||||
{
|
{
|
||||||
server.proxyDown = value;
|
aggregateProxyDown += value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (name == Global.directTag)
|
else if (name == Global.DirectTag)
|
||||||
{
|
{
|
||||||
if (type == "uplink")
|
if (type == "uplink")
|
||||||
{
|
{
|
||||||
@@ -110,6 +124,8 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
server.proxyUp = aggregateProxyUp;
|
||||||
|
server.proxyDown = aggregateProxyDown;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
76
v2rayN/ServiceLib/Handler/TaskHandler.cs
Normal file
76
v2rayN/ServiceLib/Handler/TaskHandler.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
namespace ServiceLib.Handler
|
||||||
|
{
|
||||||
|
public class TaskHandler
|
||||||
|
{
|
||||||
|
private static readonly Lazy<TaskHandler> _instance = new(() => new());
|
||||||
|
public static TaskHandler Instance => _instance.Value;
|
||||||
|
|
||||||
|
public TaskHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegUpdateTask(Config config, Action<bool, string> update)
|
||||||
|
{
|
||||||
|
Task.Run(() => UpdateTaskRunSubscription(config, update));
|
||||||
|
Task.Run(() => UpdateTaskRunGeo(config, update));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> update)
|
||||||
|
{
|
||||||
|
await Task.Delay(60000);
|
||||||
|
Logging.SaveLog("UpdateTaskRunSubscription");
|
||||||
|
|
||||||
|
var updateHandle = new UpdateHandler();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
|
||||||
|
var lstSubs = LazyConfig.Instance.SubItems()
|
||||||
|
.Where(t => t.autoUpdateInterval > 0)
|
||||||
|
.Where(t => updateTime - t.updateTime >= t.autoUpdateInterval * 60)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var item in lstSubs)
|
||||||
|
{
|
||||||
|
updateHandle.UpdateSubscriptionProcess(config, item.id, true, (bool success, string msg) =>
|
||||||
|
{
|
||||||
|
update(success, msg);
|
||||||
|
if (success)
|
||||||
|
Logging.SaveLog("subscription" + msg);
|
||||||
|
});
|
||||||
|
item.updateTime = updateTime;
|
||||||
|
ConfigHandler.AddSubItem(config, item);
|
||||||
|
|
||||||
|
await Task.Delay(5000);
|
||||||
|
}
|
||||||
|
await Task.Delay(60000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateTaskRunGeo(Config config, Action<bool, string> update)
|
||||||
|
{
|
||||||
|
var autoUpdateGeoTime = DateTime.Now;
|
||||||
|
|
||||||
|
await Task.Delay(1000 * 120);
|
||||||
|
Logging.SaveLog("UpdateTaskRunGeo");
|
||||||
|
|
||||||
|
var updateHandle = new UpdateHandler();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var dtNow = DateTime.Now;
|
||||||
|
if (config.guiItem.autoUpdateInterval > 0)
|
||||||
|
{
|
||||||
|
if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0)
|
||||||
|
{
|
||||||
|
updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
|
||||||
|
{
|
||||||
|
update(false, msg);
|
||||||
|
});
|
||||||
|
autoUpdateGeoTime = dtNow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(1000 * 3600);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +1,17 @@
|
|||||||
using DynamicData;
|
using System.Diagnostics;
|
||||||
using Splat;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Windows;
|
|
||||||
using v2rayN.Base;
|
|
||||||
using v2rayN.Mode;
|
|
||||||
using v2rayN.Resx;
|
|
||||||
using v2rayN.Tool;
|
|
||||||
|
|
||||||
namespace v2rayN.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
internal class UpdateHandle
|
public class UpdateHandler
|
||||||
{
|
{
|
||||||
private Action<bool, string> _updateFunc;
|
private Action<bool, string> _updateFunc;
|
||||||
private Config _config;
|
private Config _config;
|
||||||
|
private int _timeout = 30;
|
||||||
|
|
||||||
public event EventHandler<ResultEventArgs> AbsoluteCompleted;
|
private class ResultEventArgs
|
||||||
|
|
||||||
public class ResultEventArgs : EventArgs
|
|
||||||
{
|
{
|
||||||
public bool Success;
|
public bool Success;
|
||||||
public string Msg;
|
public string Msg;
|
||||||
@@ -34,37 +25,66 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CheckUpdateGuiN(Config config, Action<bool, string> update, bool preRelease)
|
public async Task CheckUpdateGuiN(Config config, Action<bool, string> update, bool preRelease)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_updateFunc = update;
|
_updateFunc = update;
|
||||||
var url = string.Empty;
|
var url = string.Empty;
|
||||||
|
var fileName = string.Empty;
|
||||||
|
|
||||||
DownloadHandle downloadHandle = new();
|
DownloadHandler downloadHandle = new();
|
||||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
downloadHandle.UpdateCompleted += (sender2, args) =>
|
||||||
{
|
{
|
||||||
if (args.Success)
|
if (args.Success)
|
||||||
{
|
{
|
||||||
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
|
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
|
||||||
|
_updateFunc(true, Utils.UrlEncode(fileName));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_updateFunc(false, args.Msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
downloadHandle.Error += (sender2, args) =>
|
||||||
|
{
|
||||||
|
_updateFunc(false, args.GetException().Message);
|
||||||
|
};
|
||||||
|
|
||||||
|
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, ECoreType.v2rayN));
|
||||||
|
var args = await CheckUpdateAsync(downloadHandle, ECoreType.v2rayN, preRelease);
|
||||||
|
if (args.Success)
|
||||||
|
{
|
||||||
|
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, ECoreType.v2rayN));
|
||||||
|
_updateFunc(false, args.Msg);
|
||||||
|
|
||||||
|
url = args.Url;
|
||||||
|
fileName = Utils.GetTempPath(Utils.GetGUID());
|
||||||
|
await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_updateFunc(false, args.Msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CheckUpdateCore(ECoreType type, Config config, Action<bool, string> update, bool preRelease)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_updateFunc = update;
|
||||||
|
var url = string.Empty;
|
||||||
|
var fileName = string.Empty;
|
||||||
|
|
||||||
|
DownloadHandler downloadHandle = new();
|
||||||
|
downloadHandle.UpdateCompleted += (sender2, args) =>
|
||||||
|
{
|
||||||
|
if (args.Success)
|
||||||
|
{
|
||||||
|
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
|
||||||
|
_updateFunc(false, ResUI.MsgUnpacking);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
|
_updateFunc(true, fileName);
|
||||||
fileName = Utils.UrlEncode(fileName);
|
|
||||||
Process process = new()
|
|
||||||
{
|
|
||||||
StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = "v2rayUpgrade.exe",
|
|
||||||
Arguments = $"\"{fileName}\"",
|
|
||||||
WorkingDirectory = Utils.StartupPath()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
process.Start();
|
|
||||||
if (process.Id > 0)
|
|
||||||
{
|
|
||||||
_updateFunc(true, "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -80,77 +100,25 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
_updateFunc(false, args.GetException().Message);
|
_updateFunc(false, args.GetException().Message);
|
||||||
};
|
};
|
||||||
AbsoluteCompleted += (sender2, args) =>
|
|
||||||
|
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, type));
|
||||||
|
var args = await CheckUpdateAsync(downloadHandle, type, preRelease);
|
||||||
|
if (args.Success)
|
||||||
{
|
{
|
||||||
if (args.Success)
|
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, type));
|
||||||
{
|
_updateFunc(false, args.Msg);
|
||||||
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, "v2rayN"));
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
|
|
||||||
url = args.Url;
|
url = args.Url;
|
||||||
_ = askToDownload(downloadHandle, url, true);
|
fileName = Utils.GetTempPath(Utils.GetGUID());
|
||||||
}
|
await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout);
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
Locator.Current.GetService<NoticeHandler>()?.Enqueue(args.Msg);
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, "v2rayN"));
|
|
||||||
CheckUpdateAsync(ECoreType.v2rayN, preRelease);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CheckUpdateCore(ECoreType type, Config config, Action<bool, string> update, bool preRelease)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_updateFunc = update;
|
|
||||||
var url = string.Empty;
|
|
||||||
|
|
||||||
DownloadHandle downloadHandle = new();
|
|
||||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
|
||||||
{
|
{
|
||||||
if (args.Success)
|
if (!args.Msg.IsNullOrEmpty())
|
||||||
{
|
|
||||||
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
|
|
||||||
_updateFunc(false, ResUI.MsgUnpacking);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_updateFunc(true, url);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_updateFunc(false, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
_updateFunc(false, args.Msg);
|
_updateFunc(false, args.Msg);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
downloadHandle.Error += (sender2, args) =>
|
|
||||||
{
|
|
||||||
_updateFunc(true, args.GetException().Message);
|
|
||||||
};
|
|
||||||
|
|
||||||
AbsoluteCompleted += (sender2, args) =>
|
|
||||||
{
|
|
||||||
if (args.Success)
|
|
||||||
{
|
|
||||||
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, "Core"));
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
|
|
||||||
url = args.Url;
|
|
||||||
_ = askToDownload(downloadHandle, url, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Locator.Current.GetService<NoticeHandler>()?.Enqueue(args.Msg);
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, "Core"));
|
|
||||||
CheckUpdateAsync(type, preRelease);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action<bool, string> update)
|
public void UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action<bool, string> update)
|
||||||
@@ -180,7 +148,7 @@ namespace v2rayN.Handler
|
|||||||
//_updateFunc(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
|
//_updateFunc(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!url.StartsWith(Global.httpsProtocol) && !url.StartsWith(Global.httpProtocol))
|
if (!url.StartsWith(Global.HttpsProtocol) && !url.StartsWith(Global.HttpProtocol))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -190,7 +158,7 @@ namespace v2rayN.Handler
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var downloadHandle = new DownloadHandle();
|
var downloadHandle = new DownloadHandler();
|
||||||
downloadHandle.Error += (sender2, args) =>
|
downloadHandle.Error += (sender2, args) =>
|
||||||
{
|
{
|
||||||
_updateFunc(false, $"{hashCode}{args.GetException().Message}");
|
_updateFunc(false, $"{hashCode}{args.GetException().Message}");
|
||||||
@@ -203,7 +171,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="))
|
||||||
{
|
{
|
||||||
@@ -223,15 +191,12 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
var lstUrl = new List<string>
|
var lstUrl = item.moreUrl.TrimEx().Split(",") ?? [];
|
||||||
{
|
|
||||||
item.moreUrl.TrimEx().Split(",")
|
|
||||||
};
|
|
||||||
foreach (var it in lstUrl)
|
foreach (var it in lstUrl)
|
||||||
{
|
{
|
||||||
var url2 = Utils.GetPunycode(it);
|
var url2 = Utils.GetPunycode(it);
|
||||||
@@ -247,7 +212,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);
|
||||||
}
|
}
|
||||||
@@ -266,16 +231,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
|
||||||
@@ -289,23 +254,18 @@ namespace v2rayN.Handler
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateGeoFileAll(Config config, Action<bool, string> update)
|
public async Task UpdateGeoFileAll(Config config, Action<bool, string> update)
|
||||||
{
|
{
|
||||||
Task.Run(async () =>
|
await UpdateGeoFile("geosite", _config, update);
|
||||||
{
|
await UpdateGeoFile("geoip", _config, update);
|
||||||
await UpdateGeoFile("geosite", _config, update);
|
_updateFunc(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo"));
|
||||||
await UpdateGeoFile("geoip", _config, update);
|
|
||||||
|
|
||||||
await UpdateGeoFile4Singbox("geosite", _config, false, update);
|
|
||||||
await UpdateGeoFile4Singbox("geoip", _config, true, update);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RunAvailabilityCheck(Action<bool, string> update)
|
public void RunAvailabilityCheck(Action<bool, string> update)
|
||||||
{
|
{
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var time = await (new DownloadHandle()).RunAvailabilityCheck(null);
|
var time = await (new DownloadHandler()).RunAvailabilityCheck(null);
|
||||||
|
|
||||||
update(false, string.Format(ResUI.TestMeOutput, time));
|
update(false, string.Format(ResUI.TestMeOutput, time));
|
||||||
});
|
});
|
||||||
@@ -313,44 +273,44 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
#region private
|
#region private
|
||||||
|
|
||||||
private async void CheckUpdateAsync(ECoreType type, bool preRelease)
|
private async Task<ResultEventArgs> CheckUpdateAsync(DownloadHandler downloadHandle, ECoreType type, bool preRelease)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
|
||||||
string url = coreInfo.coreReleaseApiUrl;
|
var url = coreInfo?.coreReleaseApiUrl;
|
||||||
|
|
||||||
var result = await (new DownloadHandle()).DownloadStringAsync(url, true, "");
|
var result = await downloadHandle.DownloadStringAsync(url, true, Global.AppName);
|
||||||
if (!Utils.IsNullOrEmpty(result))
|
if (!Utils.IsNullOrEmpty(result))
|
||||||
{
|
{
|
||||||
responseHandler(type, result, preRelease);
|
return await ParseDownloadUrl(type, result, preRelease);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Utils.SaveLog("StatusCode error: " + url);
|
return new ResultEventArgs(false, "");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
_updateFunc(false, ex.Message);
|
_updateFunc(false, ex.Message);
|
||||||
|
return new ResultEventArgs(false, ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取V2RayCore版本
|
/// 获取Core版本
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private SemanticVersion getCoreVersion(ECoreType type)
|
private SemanticVersion GetCoreVersion(ECoreType type)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
|
||||||
string filePath = string.Empty;
|
string filePath = string.Empty;
|
||||||
foreach (string name in coreInfo.coreExes)
|
foreach (string name in coreInfo.coreExes)
|
||||||
{
|
{
|
||||||
string vName = $"{name}.exe";
|
string vName = Utils.GetExeName(name);
|
||||||
vName = Utils.GetBinPath(vName, coreInfo.coreType);
|
vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString());
|
||||||
if (File.Exists(vName))
|
if (File.Exists(vName))
|
||||||
{
|
{
|
||||||
filePath = vName;
|
filePath = vName;
|
||||||
@@ -366,7 +326,7 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
using Process p = new();
|
using Process p = new();
|
||||||
p.StartInfo.FileName = filePath;
|
p.StartInfo.FileName = filePath.AppendQuotes();
|
||||||
p.StartInfo.Arguments = coreInfo.versionArg;
|
p.StartInfo.Arguments = coreInfo.versionArg;
|
||||||
p.StartInfo.WorkingDirectory = Utils.StartupPath();
|
p.StartInfo.WorkingDirectory = Utils.StartupPath();
|
||||||
p.StartInfo.UseShellExecute = false;
|
p.StartInfo.UseShellExecute = false;
|
||||||
@@ -388,6 +348,7 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
case ECoreType.clash:
|
case ECoreType.clash:
|
||||||
case ECoreType.clash_meta:
|
case ECoreType.clash_meta:
|
||||||
|
case ECoreType.mihomo:
|
||||||
version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value;
|
version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -399,26 +360,25 @@ namespace v2rayN.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
_updateFunc(false, ex.Message);
|
_updateFunc(false, ex.Message);
|
||||||
return new SemanticVersion("");
|
return new SemanticVersion("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void responseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease)
|
private async Task<ResultEventArgs> ParseDownloadUrl(ECoreType type, string gitHubReleaseApi, bool preRelease)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var gitHubReleases = Utils.FromJson<List<GitHubRelease>>(gitHubReleaseApi);
|
var gitHubReleases = JsonUtils.Deserialize<List<GitHubRelease>>(gitHubReleaseApi);
|
||||||
var gitHubRelease = preRelease ? gitHubReleases!.First() : gitHubReleases!.First(r => r.Prerelease == false);
|
var gitHubRelease = preRelease ? gitHubReleases?.First() : gitHubReleases?.First(r => r.Prerelease == false);
|
||||||
var version = new SemanticVersion(gitHubRelease!.TagName);
|
var version = new SemanticVersion(gitHubRelease?.TagName!);
|
||||||
var body = gitHubRelease!.Body;
|
var body = gitHubRelease?.Body;
|
||||||
|
|
||||||
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
|
|
||||||
|
|
||||||
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
|
||||||
SemanticVersion curVersion;
|
SemanticVersion curVersion;
|
||||||
string message;
|
string message;
|
||||||
string url;
|
string? url;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ECoreType.v2fly:
|
case ECoreType.v2fly:
|
||||||
@@ -426,88 +386,32 @@ namespace v2rayN.Handler
|
|||||||
case ECoreType.Xray:
|
case ECoreType.Xray:
|
||||||
case ECoreType.v2fly_v5:
|
case ECoreType.v2fly_v5:
|
||||||
{
|
{
|
||||||
curVersion = getCoreVersion(type);
|
curVersion = GetCoreVersion(type);
|
||||||
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
||||||
string osBit = "64";
|
url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"));
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
case ECoreType.clash:
|
case ECoreType.clash:
|
||||||
case ECoreType.clash_meta:
|
case ECoreType.clash_meta:
|
||||||
|
case ECoreType.mihomo:
|
||||||
{
|
{
|
||||||
curVersion = getCoreVersion(type);
|
curVersion = GetCoreVersion(type);
|
||||||
message = string.Format(ResUI.IsLatestCore, type, curVersion);
|
message = string.Format(ResUI.IsLatestCore, type, curVersion);
|
||||||
switch (RuntimeInformation.ProcessArchitecture)
|
url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"));
|
||||||
{
|
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
case ECoreType.sing_box:
|
case ECoreType.sing_box:
|
||||||
{
|
{
|
||||||
curVersion = getCoreVersion(type);
|
curVersion = GetCoreVersion(type);
|
||||||
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
|
||||||
switch (RuntimeInformation.ProcessArchitecture)
|
url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"), version);
|
||||||
{
|
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
case ECoreType.v2rayN:
|
case ECoreType.v2rayN:
|
||||||
{
|
{
|
||||||
curVersion = new SemanticVersion(FileVersionInfo.GetVersionInfo(Utils.GetExePath()).FileVersion.ToString());
|
curVersion = new SemanticVersion(Utils.GetVersionInfo());
|
||||||
message = string.Format(ResUI.IsLatestN, type, curVersion);
|
message = string.Format(ResUI.IsLatestN, type, curVersion);
|
||||||
switch (RuntimeInformation.ProcessArchitecture)
|
url = string.Format(GetUrlFromCore(coreInfo), version);
|
||||||
{
|
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -516,46 +420,52 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
if (curVersion >= version && version != new SemanticVersion(0, 0, 0))
|
if (curVersion >= version && version != new SemanticVersion(0, 0, 0))
|
||||||
{
|
{
|
||||||
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message));
|
return new ResultEventArgs(false, message);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(true, body, url));
|
return new ResultEventArgs(true, body, url);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Utils.SaveLog(ex.Message, ex);
|
Logging.SaveLog(ex.Message, ex);
|
||||||
_updateFunc(false, ex.Message);
|
_updateFunc(false, ex.Message);
|
||||||
|
return new ResultEventArgs(false, ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task askToDownload(DownloadHandle downloadHandle, string url, bool blAsk)
|
private string? GetUrlFromCore(CoreInfo? coreInfo)
|
||||||
{
|
{
|
||||||
bool blDownload = false;
|
if (Utils.IsWindows())
|
||||||
if (blAsk)
|
|
||||||
{
|
{
|
||||||
if (UI.ShowYesNo(string.Format(ResUI.DownloadYesNo, url)) == MessageBoxResult.Yes)
|
return RuntimeInformation.ProcessArchitecture switch
|
||||||
{
|
{
|
||||||
blDownload = true;
|
Architecture.Arm64 => coreInfo?.coreDownloadUrlArm64,
|
||||||
}
|
Architecture.X86 => coreInfo?.coreDownloadUrl32,
|
||||||
|
Architecture.X64 => coreInfo?.coreDownloadUrl64,
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
else
|
else if (Utils.IsLinux())
|
||||||
{
|
{
|
||||||
blDownload = true;
|
return RuntimeInformation.ProcessArchitecture switch
|
||||||
}
|
{
|
||||||
if (blDownload)
|
Architecture.Arm64 => coreInfo?.coreDownloadUrlLinuxArm64,
|
||||||
{
|
Architecture.X86 => coreInfo?.coreDownloadUrlLinux32,
|
||||||
await downloadHandle.DownloadFileAsync(url, true, 600);
|
Architecture.X64 => coreInfo?.coreDownloadUrlLinux64,
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateGeoFile(string geoName, Config config, Action<bool, string> update)
|
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);
|
||||||
|
var fileName = Utils.GetTempPath(Utils.GetGUID());
|
||||||
|
|
||||||
DownloadHandle downloadHandle = new();
|
DownloadHandler downloadHandle = new();
|
||||||
downloadHandle.UpdateCompleted += (sender2, args) =>
|
downloadHandle.UpdateCompleted += (sender2, args) =>
|
||||||
{
|
{
|
||||||
if (args.Success)
|
if (args.Success)
|
||||||
@@ -564,14 +474,8 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
|
|
||||||
if (File.Exists(fileName))
|
if (File.Exists(fileName))
|
||||||
{
|
{
|
||||||
//Global.coreTypes.ForEach(it =>
|
|
||||||
//{
|
|
||||||
// string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
|
|
||||||
// File.Copy(fileName, targetPath, true);
|
|
||||||
//});
|
|
||||||
string targetPath = Utils.GetBinPath($"{geoName}.dat");
|
string targetPath = Utils.GetBinPath($"{geoName}.dat");
|
||||||
File.Copy(fileName, targetPath, true);
|
File.Copy(fileName, targetPath, true);
|
||||||
|
|
||||||
@@ -593,55 +497,8 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
_updateFunc(false, args.GetException().Message);
|
_updateFunc(false, args.GetException().Message);
|
||||||
};
|
};
|
||||||
await askToDownload(downloadHandle, url, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateGeoFile4Singbox(string geoName, Config config, bool needStop, Action<bool, string> update)
|
await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout);
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_updateFunc = update;
|
|
||||||
var url = string.Format(Global.singboxGeoUrl, geoName);
|
|
||||||
|
|
||||||
DownloadHandle downloadHandle = new();
|
|
||||||
downloadHandle.UpdateCompleted += async (sender2, args) =>
|
|
||||||
{
|
|
||||||
if (args.Success)
|
|
||||||
{
|
|
||||||
_updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName));
|
|
||||||
var coreHandler = Locator.Current.GetService<CoreHandler>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (needStop)
|
|
||||||
{
|
|
||||||
coreHandler?.CoreStop();
|
|
||||||
await Task.Delay(3000);
|
|
||||||
}
|
|
||||||
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
|
|
||||||
if (File.Exists(fileName))
|
|
||||||
{
|
|
||||||
string targetPath = Utils.GetConfigPath($"{geoName}.db");
|
|
||||||
File.Copy(fileName, targetPath, true);
|
|
||||||
|
|
||||||
File.Delete(fileName);
|
|
||||||
}
|
|
||||||
if (needStop) coreHandler?.LoadCore();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_updateFunc(false, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_updateFunc(false, args.Msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
downloadHandle.Error += (sender2, args) =>
|
|
||||||
{
|
|
||||||
_updateFunc(false, args.GetException().Message);
|
|
||||||
};
|
|
||||||
await askToDownload(downloadHandle, url, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion private
|
#endregion private
|
||||||
11
v2rayN/ServiceLib/Models/CheckUpdateItem.cs
Normal file
11
v2rayN/ServiceLib/Models/CheckUpdateItem.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
public class CheckUpdateItem
|
||||||
|
{
|
||||||
|
public bool? isSelected { get; set; }
|
||||||
|
public string coreType { get; set; }
|
||||||
|
public string? remarks { get; set; }
|
||||||
|
public string? fileName { get; set; }
|
||||||
|
public bool? isFinished { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
17
v2rayN/ServiceLib/Models/ClashConnectionModel.cs
Normal file
17
v2rayN/ServiceLib/Models/ClashConnectionModel.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
public class ClashConnectionModel
|
||||||
|
{
|
||||||
|
public string id { get; set; }
|
||||||
|
public string network { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string host { get; set; }
|
||||||
|
public ulong upload { get; set; }
|
||||||
|
public ulong download { get; set; }
|
||||||
|
public string uploadTraffic { get; set; }
|
||||||
|
public string downloadTraffic { get; set; }
|
||||||
|
public double time { get; set; }
|
||||||
|
public string elapsed { get; set; }
|
||||||
|
public string chain { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
37
v2rayN/ServiceLib/Models/ClashConnections.cs
Normal file
37
v2rayN/ServiceLib/Models/ClashConnections.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
public class ClashConnections
|
||||||
|
{
|
||||||
|
public ulong downloadTotal { get; set; }
|
||||||
|
public ulong uploadTotal { get; set; }
|
||||||
|
public List<ConnectionItem>? connections { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ConnectionItem
|
||||||
|
{
|
||||||
|
public string id { get; set; } = string.Empty;
|
||||||
|
public MetadataItem metadata { get; set; }
|
||||||
|
public ulong upload { get; set; }
|
||||||
|
public ulong download { get; set; }
|
||||||
|
public DateTime start { get; set; }
|
||||||
|
public List<string>? chains { get; set; }
|
||||||
|
public string rule { get; set; }
|
||||||
|
public string rulePayload { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MetadataItem
|
||||||
|
{
|
||||||
|
public string network { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string sourceIP { get; set; }
|
||||||
|
public string destinationIP { get; set; }
|
||||||
|
public string sourcePort { get; set; }
|
||||||
|
public string destinationPort { get; set; }
|
||||||
|
public string host { get; set; }
|
||||||
|
public string nsMode { get; set; }
|
||||||
|
public object uid { get; set; }
|
||||||
|
public string process { get; set; }
|
||||||
|
public string processPath { get; set; }
|
||||||
|
public string remoteDestination { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
17
v2rayN/ServiceLib/Models/ClashProviders.cs
Normal file
17
v2rayN/ServiceLib/Models/ClashProviders.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using static ServiceLib.Models.ClashProxies;
|
||||||
|
|
||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
public class ClashProviders
|
||||||
|
{
|
||||||
|
public Dictionary<String, ProvidersItem> providers { get; set; }
|
||||||
|
|
||||||
|
public class ProvidersItem
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
public ProxiesItem[] proxies { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string vehicleType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
v2rayN/ServiceLib/Models/ClashProxies.cs
Normal file
24
v2rayN/ServiceLib/Models/ClashProxies.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
public class ClashProxies
|
||||||
|
{
|
||||||
|
public Dictionary<String, ProxiesItem> proxies { get; set; }
|
||||||
|
|
||||||
|
public class ProxiesItem
|
||||||
|
{
|
||||||
|
public string[] all { get; set; }
|
||||||
|
public List<HistoryItem> history { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public bool udp { get; set; }
|
||||||
|
public string now { get; set; }
|
||||||
|
public int delay { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HistoryItem
|
||||||
|
{
|
||||||
|
public string time { get; set; }
|
||||||
|
public int delay { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
v2rayN/ServiceLib/Models/ClashProxyModel.cs
Normal file
18
v2rayN/ServiceLib/Models/ClashProxyModel.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class ClashProxyModel
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
|
||||||
|
public string type { get; set; }
|
||||||
|
|
||||||
|
public string now { get; set; }
|
||||||
|
|
||||||
|
public int delay { get; set; }
|
||||||
|
|
||||||
|
public string delayName { get; set; }
|
||||||
|
|
||||||
|
public bool isActive { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
public class ComboItem
|
public class ComboItem
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 本软件配置文件实体类
|
/// 本软件配置文件实体类
|
||||||
@@ -10,10 +10,24 @@
|
|||||||
|
|
||||||
public string indexId { get; set; }
|
public string indexId { get; set; }
|
||||||
public string subIndexId { get; set; }
|
public string subIndexId { 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; }
|
||||||
|
|
||||||
|
public bool IsRunningCore(ECoreType type)
|
||||||
|
{
|
||||||
|
if (type == ECoreType.Xray && runningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5 or ECoreType.SagerNet)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (type == ECoreType.clash && runningCoreType is ECoreType.sing_box or ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion property
|
#endregion property
|
||||||
|
|
||||||
#region other entities
|
#region other entities
|
||||||
@@ -24,11 +38,15 @@
|
|||||||
public GrpcItem grpcItem { get; set; }
|
public GrpcItem grpcItem { get; set; }
|
||||||
public RoutingBasicItem routingBasicItem { get; set; }
|
public RoutingBasicItem routingBasicItem { get; set; }
|
||||||
public GUIItem guiItem { get; set; }
|
public GUIItem guiItem { get; set; }
|
||||||
|
public MsgUIItem msgUIItem { get; set; }
|
||||||
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 Mux4RayItem mux4RayItem { get; set; }
|
||||||
public Mux4SboxItem mux4SboxItem { get; set; }
|
public Mux4SboxItem mux4SboxItem { get; set; }
|
||||||
public HysteriaItem hysteriaItem { get; set; }
|
public HysteriaItem hysteriaItem { get; set; }
|
||||||
|
public ClashUIItem clashUIItem { get; set; }
|
||||||
|
public SystemProxyItem systemProxyItem { 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,4 @@
|
|||||||
using System.Windows.Input;
|
namespace ServiceLib.Models
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CoreBasicItem
|
public class CoreBasicItem
|
||||||
@@ -31,6 +29,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 +45,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; }
|
||||||
@@ -105,14 +107,23 @@ namespace v2rayN.Mode
|
|||||||
public bool enableLog { get; set; } = true;
|
public bool enableLog { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class MsgUIItem
|
||||||
|
{
|
||||||
|
public string? mainMsgFilter { get; set; }
|
||||||
|
public bool? autoRefresh { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
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 EGirdOrientation mainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
||||||
public bool colorModeDark { get; set; }
|
public bool colorModeDark { get; set; }
|
||||||
public bool followSystemTheme { get; set; }
|
public bool followSystemTheme { get; set; }
|
||||||
public string? colorPrimaryName { get; set; }
|
public string? colorPrimaryName { get; set; }
|
||||||
@@ -121,10 +132,9 @@ namespace v2rayN.Mode
|
|||||||
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 bool showTrayTip { get; set; }
|
|
||||||
public List<ColumnItem> mainColumnItem { get; set; }
|
public List<ColumnItem> mainColumnItem { get; set; }
|
||||||
|
public bool showInTaskbar { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -145,7 +155,7 @@ namespace v2rayN.Mode
|
|||||||
|
|
||||||
public bool Shift { get; set; }
|
public bool Shift { get; set; }
|
||||||
|
|
||||||
public Key? KeyCode { get; set; }
|
public int? KeyCode { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -164,6 +174,7 @@ namespace v2rayN.Mode
|
|||||||
public string stack { get; set; }
|
public string stack { get; set; }
|
||||||
public int mtu { get; set; }
|
public int mtu { get; set; }
|
||||||
public bool enableExInbound { get; set; }
|
public bool enableExInbound { get; set; }
|
||||||
|
public bool enableIPv6Address { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -177,13 +188,8 @@ 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 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; }
|
||||||
@@ -197,14 +203,20 @@ namespace v2rayN.Mode
|
|||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Mux4RayItem
|
||||||
|
{
|
||||||
|
public int? concurrency { get; set; }
|
||||||
|
public int? xudpConcurrency { get; set; }
|
||||||
|
public string? xudpProxyUDP443 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Mux4SboxItem
|
public class Mux4SboxItem
|
||||||
{
|
{
|
||||||
public string protocol { get; set; }
|
public string protocol { get; set; }
|
||||||
public int max_connections { get; set; }
|
public int max_connections { get; set; }
|
||||||
public int min_streams { get; set; }
|
public bool? padding { get; set; }
|
||||||
public int max_streams { get; set; }
|
|
||||||
public bool padding { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -213,4 +225,27 @@ namespace v2rayN.Mode
|
|||||||
public int up_mbps { get; set; }
|
public int up_mbps { get; set; }
|
||||||
public int down_mbps { get; set; }
|
public int down_mbps { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class ClashUIItem
|
||||||
|
{
|
||||||
|
public ERuleMode ruleMode { get; set; }
|
||||||
|
public bool enableIPv6 { get; set; }
|
||||||
|
public bool enableMixinContent { get; set; }
|
||||||
|
public int proxiesSorting { get; set; }
|
||||||
|
public bool proxiesAutoRefresh { get; set; }
|
||||||
|
public int proxiesAutoDelayTestInterval { get; set; } = 10;
|
||||||
|
public int connectionsSorting { get; set; }
|
||||||
|
public bool connectionsAutoRefresh { get; set; }
|
||||||
|
public int connectionsRefreshInterval { get; set; } = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class SystemProxyItem
|
||||||
|
{
|
||||||
|
public ESysProxyType sysProxyType { get; set; }
|
||||||
|
public string systemProxyExceptions { get; set; }
|
||||||
|
public bool notProxyLocalAddress { get; set; } = true;
|
||||||
|
public string systemProxyAdvancedProtocol { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CoreInfo
|
public class CoreInfo
|
||||||
@@ -18,6 +18,9 @@
|
|||||||
public string coreDownloadUrl64 { get; set; }
|
public string coreDownloadUrl64 { get; set; }
|
||||||
|
|
||||||
public string coreDownloadUrlArm64 { get; set; }
|
public string coreDownloadUrlArm64 { get; set; }
|
||||||
|
public string? coreDownloadUrlLinux32 { get; set; }
|
||||||
|
public string? coreDownloadUrlLinux64 { get; set; }
|
||||||
|
public string? coreDownloadUrlLinuxArm64 { get; set; }
|
||||||
|
|
||||||
public string match { get; set; }
|
public string match { get; set; }
|
||||||
public string versionArg { get; set; }
|
public string versionArg { get; set; }
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class DNSItem
|
public class DNSItem
|
||||||
@@ -15,5 +15,6 @@ namespace v2rayN.Mode
|
|||||||
public string? normalDNS { get; set; }
|
public string? normalDNS { get; set; }
|
||||||
public string? tunDNS { get; set; }
|
public string? tunDNS { get; set; }
|
||||||
public string? domainStrategy4Freedom { get; set; }
|
public string? domainStrategy4Freedom { get; set; }
|
||||||
|
public string? domainDNSAddress { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
68
v2rayN/ServiceLib/Models/GitHubRelease.cs
Normal file
68
v2rayN/ServiceLib/Models/GitHubRelease.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace ServiceLib.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 ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileExItem
|
public class ProfileExItem
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
using v2rayN.Base;
|
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileItem
|
public class ProfileItem
|
||||||
@@ -48,17 +47,12 @@ namespace v2rayN.Mode
|
|||||||
}
|
}
|
||||||
switch (configType)
|
switch (configType)
|
||||||
{
|
{
|
||||||
case EConfigType.VMess:
|
case EConfigType.Custom:
|
||||||
case EConfigType.Shadowsocks:
|
summary += string.Format("[{1}]{0}", remarks, coreType.ToString());
|
||||||
case EConfigType.Socks:
|
|
||||||
case EConfigType.VLESS:
|
|
||||||
case EConfigType.Trojan:
|
|
||||||
case EConfigType.Hysteria2:
|
|
||||||
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;
|
||||||
@@ -78,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;
|
||||||
}
|
}
|
||||||
@@ -184,7 +178,7 @@ namespace v2rayN.Mode
|
|||||||
|
|
||||||
public ECoreType? coreType { get; set; }
|
public ECoreType? coreType { get; set; }
|
||||||
|
|
||||||
public int preSocksPort { get; set; }
|
public int? preSocksPort { get; set; }
|
||||||
|
|
||||||
public string fingerprint { get; set; }
|
public string fingerprint { get; set; }
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ProfileItemModel : ProfileItem
|
public class ProfileItemModel : ProfileItem
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RoutingItem
|
public class RoutingItem
|
||||||
@@ -15,6 +15,7 @@ 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 string domainStrategy4Singbox { get; set; }
|
||||||
public int sort { get; set; }
|
public int sort { get; set; }
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RoutingItemModel : RoutingItem
|
public class RoutingItemModel : RoutingItem
|
||||||
26
v2rayN/ServiceLib/Models/RulesItem.cs
Normal file
26
v2rayN/ServiceLib/Models/RulesItem.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class RulesItem
|
||||||
|
{
|
||||||
|
public string id { get; set; }
|
||||||
|
public string? type { get; set; }
|
||||||
|
|
||||||
|
public string? port { get; set; }
|
||||||
|
public string? network { 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 List<string>? process { get; set; }
|
||||||
|
|
||||||
|
public bool enabled { get; set; } = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RulesItemModel : RulesItem
|
public class RulesItemModel : RulesItem
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal class ServerSpeedItem : ServerStatItem
|
public class ServerSpeedItem : ServerStatItem
|
||||||
{
|
{
|
||||||
public long proxyUp
|
public long proxyUp
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ServerStatItem
|
public class ServerStatItem
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal class ServerTestItem
|
public class ServerTestItem
|
||||||
{
|
{
|
||||||
public string indexId { get; set; }
|
public string indexId { get; set; }
|
||||||
public string address { get; set; }
|
public string address { get; set; }
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
public class SingboxConfig
|
public class SingboxConfig
|
||||||
{
|
{
|
||||||
public Log4Sbox log { get; set; }
|
public Log4Sbox log { get; set; }
|
||||||
public object dns { get; set; }
|
public Dns4Sbox? dns { get; set; }
|
||||||
public List<Inbound4Sbox> inbounds { get; set; }
|
public List<Inbound4Sbox> inbounds { get; set; }
|
||||||
public List<Outbound4Sbox> outbounds { get; set; }
|
public List<Outbound4Sbox> outbounds { get; set; }
|
||||||
public Route4Sbox route { get; set; }
|
public Route4Sbox route { get; set; }
|
||||||
public Experimental4Sbox experimental { get; set; }
|
public Experimental4Sbox? experimental { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Log4Sbox
|
public class Log4Sbox
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
public bool? disabled { get; set; }
|
public bool? disabled { get; set; }
|
||||||
public string level { get; set; }
|
public string level { get; set; }
|
||||||
public string output { get; set; }
|
public string output { get; set; }
|
||||||
public bool timestamp { get; set; }
|
public bool? timestamp { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Dns4Sbox
|
public class Dns4Sbox
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
public bool? disable_expire { get; set; }
|
public bool? disable_expire { get; set; }
|
||||||
public bool? independent_cache { get; set; }
|
public bool? independent_cache { get; set; }
|
||||||
public bool? reverse_mapping { get; set; }
|
public bool? reverse_mapping { get; set; }
|
||||||
|
public string? client_subnet { get; set; }
|
||||||
public Fakeip4Sbox? fakeip { get; set; }
|
public Fakeip4Sbox? fakeip { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,19 +36,24 @@
|
|||||||
{
|
{
|
||||||
public bool? auto_detect_interface { get; set; }
|
public bool? auto_detect_interface { get; set; }
|
||||||
public List<Rule4Sbox> rules { get; set; }
|
public List<Rule4Sbox> rules { get; set; }
|
||||||
|
public List<Ruleset4Sbox>? rule_set { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Rule4Sbox
|
public class Rule4Sbox
|
||||||
{
|
{
|
||||||
public string outbound { get; set; }
|
public string? outbound { get; set; }
|
||||||
public string server { get; set; }
|
public string? server { get; set; }
|
||||||
public bool? disable_cache { get; set; }
|
public bool? disable_cache { get; set; }
|
||||||
|
public string? type { get; set; }
|
||||||
|
public string? mode { get; set; }
|
||||||
|
public bool? ip_is_private { get; set; }
|
||||||
|
public string? client_subnet { get; set; }
|
||||||
|
public bool? invert { get; set; }
|
||||||
|
public string? clash_mode { get; set; }
|
||||||
public List<string>? inbound { get; set; }
|
public List<string>? inbound { get; set; }
|
||||||
public List<string>? protocol { get; set; }
|
public List<string>? protocol { get; set; }
|
||||||
public string type { get; set; }
|
public List<string>? network { get; set; }
|
||||||
public string mode { get; set; }
|
|
||||||
public string network { get; set; }
|
|
||||||
public List<int>? port { get; set; }
|
public List<int>? port { get; set; }
|
||||||
public List<string>? port_range { get; set; }
|
public List<string>? port_range { get; set; }
|
||||||
public List<string>? geosite { get; set; }
|
public List<string>? geosite { get; set; }
|
||||||
@@ -58,8 +64,9 @@
|
|||||||
public List<string>? geoip { get; set; }
|
public List<string>? geoip { get; set; }
|
||||||
public List<string>? ip_cidr { get; set; }
|
public List<string>? ip_cidr { get; set; }
|
||||||
public List<string>? source_ip_cidr { get; set; }
|
public List<string>? source_ip_cidr { get; set; }
|
||||||
|
|
||||||
public List<string>? process_name { get; set; }
|
public List<string>? process_name { get; set; }
|
||||||
|
public List<string>? rule_set { get; set; }
|
||||||
|
public List<Rule4Sbox>? rules { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -72,7 +79,7 @@
|
|||||||
public string? domain_strategy { get; set; }
|
public string? domain_strategy { get; set; }
|
||||||
public string interface_name { get; set; }
|
public string interface_name { get; set; }
|
||||||
public string inet4_address { get; set; }
|
public string inet4_address { get; set; }
|
||||||
public string inet6_address { get; set; }
|
public string? inet6_address { get; set; }
|
||||||
public int? mtu { get; set; }
|
public int? mtu { get; set; }
|
||||||
public bool? auto_route { get; set; }
|
public bool? auto_route { get; set; }
|
||||||
public bool? strict_route { get; set; }
|
public bool? strict_route { get; set; }
|
||||||
@@ -93,7 +100,7 @@
|
|||||||
{
|
{
|
||||||
public string type { get; set; }
|
public string type { get; set; }
|
||||||
public string tag { get; set; }
|
public string tag { get; set; }
|
||||||
public string server { get; set; }
|
public string? server { get; set; }
|
||||||
public int? server_port { get; set; }
|
public int? server_port { get; set; }
|
||||||
public string uuid { get; set; }
|
public string uuid { get; set; }
|
||||||
public string security { get; set; }
|
public string security { get; set; }
|
||||||
@@ -105,16 +112,27 @@
|
|||||||
public int? recv_window_conn { get; set; }
|
public int? recv_window_conn { get; set; }
|
||||||
public int? recv_window { get; set; }
|
public int? recv_window { get; set; }
|
||||||
public bool? disable_mtu_discovery { get; set; }
|
public bool? disable_mtu_discovery { get; set; }
|
||||||
public string detour { get; set; }
|
public string? detour { get; set; }
|
||||||
public string method { get; set; }
|
public string method { get; set; }
|
||||||
public string username { get; set; }
|
public string username { get; set; }
|
||||||
public string password { get; set; }
|
public string password { get; set; }
|
||||||
|
public string congestion_control { get; set; }
|
||||||
public string? version { get; set; }
|
public string? version { get; set; }
|
||||||
public string? network { get; set; }
|
public string? network { get; set; }
|
||||||
public string packet_encoding { get; set; }
|
public string? packet_encoding { get; set; }
|
||||||
public Tls4Sbox tls { get; set; }
|
public string[]? local_address { get; set; }
|
||||||
public Multiplex4Sbox multiplex { get; set; }
|
public string? private_key { get; set; }
|
||||||
public Transport4Sbox transport { 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 List<string>? outbounds { get; set; }
|
||||||
|
public bool? interrupt_exist_connections { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Tls4Sbox
|
public class Tls4Sbox
|
||||||
@@ -132,9 +150,7 @@
|
|||||||
public bool enabled { get; set; }
|
public bool enabled { get; set; }
|
||||||
public string protocol { get; set; }
|
public string protocol { get; set; }
|
||||||
public int max_connections { get; set; }
|
public int max_connections { get; set; }
|
||||||
public int min_streams { get; set; }
|
public bool? padding { get; set; }
|
||||||
public int max_streams { get; set; }
|
|
||||||
public bool padding { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Utls4Sbox
|
public class Utls4Sbox
|
||||||
@@ -152,14 +168,14 @@
|
|||||||
|
|
||||||
public class Transport4Sbox
|
public class Transport4Sbox
|
||||||
{
|
{
|
||||||
public string type { get; set; }
|
public string? type { get; set; }
|
||||||
public List<string>? host { get; set; }
|
public object? host { get; set; }
|
||||||
public string? path { get; set; }
|
public string? path { get; set; }
|
||||||
public Headers4Sbox? headers { get; set; }
|
public Headers4Sbox? headers { get; set; }
|
||||||
|
|
||||||
public string service_name { get; set; }
|
public string? service_name { get; set; }
|
||||||
public string idle_timeout { get; set; }
|
public string? idle_timeout { get; set; }
|
||||||
public string ping_timeout { get; set; }
|
public string? ping_timeout { get; set; }
|
||||||
public bool? permit_without_stream { get; set; }
|
public bool? permit_without_stream { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,19 +184,28 @@
|
|||||||
public string? Host { get; set; }
|
public string? Host { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class HyObfs4Sbox
|
||||||
|
{
|
||||||
|
public string? type { get; set; }
|
||||||
|
public string? password { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class Server4Sbox
|
public class Server4Sbox
|
||||||
{
|
{
|
||||||
public string tag { get; set; }
|
public string? tag { get; set; }
|
||||||
public string address { get; set; }
|
public string? address { get; set; }
|
||||||
public string address_resolver { get; set; }
|
public string? address_resolver { get; set; }
|
||||||
public string strategy { get; set; }
|
public string? address_strategy { get; set; }
|
||||||
public string detour { get; set; }
|
public string? strategy { get; set; }
|
||||||
|
public string? detour { get; set; }
|
||||||
|
public string? client_subnet { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Experimental4Sbox
|
public class Experimental4Sbox
|
||||||
{
|
{
|
||||||
public V2ray_Api4Sbox v2ray_api { get; set; }
|
public CacheFile4Sbox? cache_file { get; set; }
|
||||||
public Clash_Api4Sbox clash_api { get; set; }
|
public V2ray_Api4Sbox? v2ray_api { get; set; }
|
||||||
|
public Clash_Api4Sbox? clash_api { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class V2ray_Api4Sbox
|
public class V2ray_Api4Sbox
|
||||||
@@ -191,8 +216,8 @@
|
|||||||
|
|
||||||
public class Clash_Api4Sbox
|
public class Clash_Api4Sbox
|
||||||
{
|
{
|
||||||
public string external_controller { get; set; }
|
public string? external_controller { get; set; }
|
||||||
public bool store_selected { get; set; }
|
public bool? store_selected { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Stats4Sbox
|
public class Stats4Sbox
|
||||||
@@ -209,4 +234,23 @@
|
|||||||
public string inet4_range { get; set; }
|
public string inet4_range { get; set; }
|
||||||
public string inet6_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; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
12
v2rayN/ServiceLib/Models/SpeedTestResult.cs
Normal file
12
v2rayN/ServiceLib/Models/SpeedTestResult.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class SpeedTestResult
|
||||||
|
{
|
||||||
|
public string? IndexId { get; set; }
|
||||||
|
|
||||||
|
public string? Delay { get; set; }
|
||||||
|
|
||||||
|
public string? Speed { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
public class SsSIP008
|
public class SsSIP008
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class SubItem
|
public class SubItem
|
||||||
@@ -27,5 +27,11 @@ 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; }
|
||||||
|
|
||||||
|
public int? preSocksPort { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace v2rayN.Mode
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
internal class SysproxyConfig
|
public 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,13 +1,17 @@
|
|||||||
using Newtonsoft.Json;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace v2rayN.Mode
|
namespace ServiceLib.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>
|
||||||
@@ -32,7 +36,7 @@ namespace v2rayN.Mode
|
|||||||
public API4Ray api { get; set; }
|
public API4Ray api { get; set; }
|
||||||
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Policy4Ray policy;
|
public Policy4Ray policy { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DNS 配置
|
/// DNS 配置
|
||||||
@@ -56,13 +60,13 @@ namespace v2rayN.Mode
|
|||||||
|
|
||||||
public class Policy4Ray
|
public class Policy4Ray
|
||||||
{
|
{
|
||||||
public SystemPolicy4Ray system;
|
public SystemPolicy4Ray system { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SystemPolicy4Ray
|
public class SystemPolicy4Ray
|
||||||
{
|
{
|
||||||
public bool statsOutboundUplink;
|
public bool statsOutboundUplink { get; set; }
|
||||||
public bool statsOutboundDownlink;
|
public bool statsOutboundDownlink { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Log4Ray
|
public class Log4Ray
|
||||||
@@ -191,7 +195,7 @@ namespace v2rayN.Mode
|
|||||||
public class Sniffing4Ray
|
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; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +232,7 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<VnextItem4Ray> vnext { get; set; }
|
public List<VnextItem4Ray>? vnext { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -249,6 +253,8 @@ namespace v2rayN.Mode
|
|||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? userLevel { get; set; }
|
public int? userLevel { get; set; }
|
||||||
|
|
||||||
|
public FragmentItem4Ray? fragment { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VnextItem4Ray
|
public class VnextItem4Ray
|
||||||
@@ -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
|
||||||
@@ -332,20 +338,15 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int level { get; set; }
|
public int? level { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Mux4Ray
|
public class Mux4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public bool enabled { get; set; }
|
public bool enabled { get; set; }
|
||||||
|
public int? concurrency { get; set; }
|
||||||
/// <summary>
|
public int? xudpConcurrency { get; set; }
|
||||||
///
|
public string? xudpProxyUDP443 { get; set; }
|
||||||
/// </summary>
|
|
||||||
public int concurrency { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Response4Ray
|
public class Response4Ray
|
||||||
@@ -364,6 +365,12 @@ namespace v2rayN.Mode
|
|||||||
public List<string> servers { get; set; }
|
public List<string> servers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class DnsServer4Ray
|
||||||
|
{
|
||||||
|
public string? address { get; set; }
|
||||||
|
public List<string>? domains { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class Routing4Ray
|
public class Routing4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -374,30 +381,47 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string domainMatcher { get; set; }
|
public string? domainMatcher { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<RulesItem4Ray> rules { get; set; }
|
public List<RulesItem4Ray> rules { get; set; }
|
||||||
|
|
||||||
|
public List<BalancersItem4Ray>? balancers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class RulesItem4Ray
|
public class RulesItem4Ray
|
||||||
{
|
{
|
||||||
public string type { get; set; }
|
public string? type { get; set; }
|
||||||
|
|
||||||
public string port { get; set; }
|
public string? port { get; set; }
|
||||||
|
public string? network { get; set; }
|
||||||
|
|
||||||
public List<string> inboundTag { get; set; }
|
public List<string>? inboundTag { get; set; }
|
||||||
|
|
||||||
public string outboundTag { get; set; }
|
public string? outboundTag { get; set; }
|
||||||
|
|
||||||
public List<string> ip { get; set; }
|
public string? balancerTag { get; set; }
|
||||||
|
|
||||||
public List<string> domain { get; set; }
|
public List<string>? ip { get; set; }
|
||||||
|
|
||||||
public List<string> protocol { get; set; }
|
public List<string>? domain { get; set; }
|
||||||
|
|
||||||
|
public List<string>? protocol { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BalancersItem4Ray
|
||||||
|
{
|
||||||
|
public List<string>? selector { get; set; }
|
||||||
|
public BalancersStrategy4Ray? strategy { get; set; }
|
||||||
|
public string? tag { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BalancersStrategy4Ray
|
||||||
|
{
|
||||||
|
public string? type { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StreamSettings4Ray
|
public class StreamSettings4Ray
|
||||||
@@ -415,42 +439,57 @@ namespace v2rayN.Mode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TlsSettings4Ray tlsSettings { get; set; }
|
public TlsSettings4Ray? tlsSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tcp传输额外设置
|
/// Tcp传输额外设置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TcpSettings4Ray tcpSettings { get; set; }
|
public TcpSettings4Ray? tcpSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Kcp传输额外设置
|
/// Kcp传输额外设置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public KcpSettings4Ray kcpSettings { get; set; }
|
public KcpSettings4Ray? kcpSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ws传输额外设置
|
/// ws传输额外设置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public WsSettings4Ray wsSettings { get; set; }
|
public WsSettings4Ray? wsSettings { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public SplithttpSettings4Ray? splithttpSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// h2传输额外设置
|
/// h2传输额外设置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HttpSettings4Ray httpSettings { get; set; }
|
public HttpSettings4Ray? httpSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// QUIC
|
/// QUIC
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public QuicSettings4Ray quicSettings { get; set; }
|
public QuicSettings4Ray? quicSettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// VLESS only
|
/// VLESS only
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TlsSettings4Ray realitySettings { get; set; }
|
public TlsSettings4Ray? realitySettings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// grpc
|
/// grpc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GrpcSettings4Ray grpcSettings { get; set; }
|
public GrpcSettings4Ray? grpcSettings { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// sockopt
|
||||||
|
/// </summary>
|
||||||
|
public Sockopt4Ray? sockopt { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TlsSettings4Ray
|
public class TlsSettings4Ray
|
||||||
@@ -472,7 +511,7 @@ namespace v2rayN.Mode
|
|||||||
|
|
||||||
public string? fingerprint { get; set; }
|
public string? fingerprint { get; set; }
|
||||||
|
|
||||||
public bool? show { get; set; } = false;
|
public bool? show { get; set; }
|
||||||
public string? publicKey { get; set; }
|
public string? publicKey { get; set; }
|
||||||
public string? shortId { get; set; }
|
public string? shortId { get; set; }
|
||||||
public string? spiderX { get; set; }
|
public string? spiderX { get; set; }
|
||||||
@@ -575,10 +614,34 @@ 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 HttpupgradeSettings4Ray
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string? path { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string? host { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SplithttpSettings4Ray
|
||||||
|
{
|
||||||
|
public string? path { get; set; }
|
||||||
|
|
||||||
|
public string? host { get; set; }
|
||||||
|
|
||||||
|
public int? maxUploadSize { get; set; }
|
||||||
|
|
||||||
|
public int? maxConcurrentUploads { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class HttpSettings4Ray
|
public class HttpSettings4Ray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -612,7 +675,8 @@ namespace v2rayN.Mode
|
|||||||
|
|
||||||
public class GrpcSettings4Ray
|
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; }
|
||||||
@@ -632,4 +696,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 ServiceLib.Models
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tcp伪装http的Request,只要Host
|
/// Tcp伪装http的Request,只要Host
|
||||||
44
v2rayN/ServiceLib/Models/VmessQRCode.cs
Normal file
44
v2rayN/ServiceLib/Models/VmessQRCode.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace ServiceLib.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// https://github.com/2dust/v2rayN/wiki/
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -117,9 +117,6 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<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>
|
||||||
<data name="BatchExportSubscriptionSuccessfully" xml:space="preserve">
|
|
||||||
<value>صادرات دسته ای محتوای اشتراک به کلیپ بورد با موفقیت انجام شد</value>
|
|
||||||
</data>
|
|
||||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||||
<value>Batch export share URL to clipboard successfully</value>
|
<value>Batch export share URL to clipboard successfully</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -159,9 +156,6 @@
|
|||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>لطفا فرمت صحیح پورت سرور را پر کنید</value>
|
<value>لطفا فرمت صحیح پورت سرور را پر کنید</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillKcpParameters" xml:space="preserve">
|
|
||||||
<value>لطفاً پارامترهای KCP را به درستی پر کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||||
<value>لطفاً پورت گوش دادن محلی را پر کنید</value>
|
<value>لطفاً پورت گوش دادن محلی را پر کنید</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -174,15 +168,9 @@
|
|||||||
<data name="FillUUID" xml:space="preserve">
|
<data name="FillUUID" xml:space="preserve">
|
||||||
<value>لطفا شناسه کاربری را وارد کنید</value>
|
<value>لطفا شناسه کاربری را وارد کنید</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectClientConfiguration" xml:space="preserve">
|
|
||||||
<value>فایل پیکربندی مشتری صحیح نیست، لطفا بررسی کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||||
<value>پیکربندی درستی نیست، لطفا بررسی کنید</value>
|
<value>پیکربندی درستی نیست، لطفا بررسی کنید</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectServerConfiguration" xml:space="preserve">
|
|
||||||
<value>فایل پیکربندی سرور صحیح نیست، لطفا بررسی کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="InitialConfiguration" xml:space="preserve">
|
<data name="InitialConfiguration" xml:space="preserve">
|
||||||
<value>پیکربندی اولیه</value>
|
<value>پیکربندی اولیه</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -267,9 +255,6 @@
|
|||||||
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
||||||
<value>Non-VMess or ss protocol</value>
|
<value>Non-VMess or ss protocol</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NonVmessService" xml:space="preserve">
|
|
||||||
<value> non-standard service, this feature is invalid</value>
|
|
||||||
</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>
|
||||||
</data>
|
</data>
|
||||||
@@ -415,15 +400,9 @@
|
|||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>Please browse to import server configuration</value>
|
<value>Please browse to import server configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SystemProxy" xml:space="preserve">
|
|
||||||
<value>پروکسی سیستم</value>
|
|
||||||
</data>
|
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>درحال تست کردن...</value>
|
<value>درحال تست کردن...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TooManyServersTip" xml:space="preserve">
|
|
||||||
<value>تعداد سرورها خیلی زیاد است، لطفا رابط اصلی را باز کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="LabLAN" xml:space="preserve">
|
<data name="LabLAN" xml:space="preserve">
|
||||||
<value>LAN</value>
|
<value>LAN</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -529,9 +508,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>
|
||||||
@@ -544,18 +520,12 @@
|
|||||||
<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">
|
|
||||||
<value>وضعیت سرویس فعلی را تست کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>سرور انتخابی را برای پیکربندی کلاینت صادر کنید</value>
|
<value>سرور انتخابی را برای پیکربندی کلاینت صادر کنید</value>
|
||||||
</data>
|
</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>
|
||||||
<data name="menuExport2SubContent" xml:space="preserve">
|
|
||||||
<value>اشتراک (base64) را به کلیپ بورد صادر کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>یک سرور پیکربندی سفارشی اضافه شود</value>
|
<value>یک سرور پیکربندی سفارشی اضافه شود</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -586,9 +556,6 @@
|
|||||||
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
||||||
<value>کپی همه</value>
|
<value>کپی همه</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMsgViewFilter" xml:space="preserve">
|
|
||||||
<value>فیلترهای پیام را تنظیم کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
||||||
<value>انتخاب همه (Ctrl+A)</value>
|
<value>انتخاب همه (Ctrl+A)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -701,7 +668,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 sing-box 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>
|
||||||
@@ -958,6 +925,9 @@
|
|||||||
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
||||||
<value>فقط مسیر</value>
|
<value>فقط مسیر</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||||
|
<value>يەرلىك (Intranet) ئادرېسلارغا ۋاكالەتچى مۇلازىمېتىر ئىشلەتمەڭ</value>
|
||||||
|
</data>
|
||||||
<data name="menuMixedTestServer" xml:space="preserve">
|
<data name="menuMixedTestServer" xml:space="preserve">
|
||||||
<value>One-click test Latency and speed (Ctrl+E)</value>
|
<value>One-click test Latency and speed (Ctrl+E)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -988,15 +958,6 @@
|
|||||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||||
<value>تنظیمات TunMode</value>
|
<value>تنظیمات TunMode</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
|
|
||||||
<value>Direct IP CIDR, separated by commas (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
|
|
||||||
<value>Direct Process name, separated by commas (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
|
|
||||||
<value>نمایش کنسول</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsDefUserAgent" xml:space="preserve">
|
<data name="TbSettingsDefUserAgent" xml:space="preserve">
|
||||||
<value>User-Agent</value>
|
<value>User-Agent</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1006,4 +967,70 @@
|
|||||||
<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>
|
||||||
|
<data name="TbSorting" xml:space="preserve">
|
||||||
|
<value>مرتب سازی</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDefault" xml:space="preserve">
|
||||||
|
<value>Default</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDelay" xml:space="preserve">
|
||||||
|
<value>تاخیر</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDownSpeed" xml:space="preserve">
|
||||||
|
<value>سرعت دانلود</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDownTraffic" xml:space="preserve">
|
||||||
|
<value>ترافیک دانلود</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingName" xml:space="preserve">
|
||||||
|
<value>نام</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingTime" xml:space="preserve">
|
||||||
|
<value>زمان</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingUpSpeed" xml:space="preserve">
|
||||||
|
<value>سرعت اپلود</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingUpTraffic" xml:space="preserve">
|
||||||
|
<value>ترافیک آپلود</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConnections" xml:space="preserve">
|
||||||
|
<value>اتصالات</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuConnectionClose" xml:space="preserve">
|
||||||
|
<value>بستن اتصال</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuConnectionCloseAll" xml:space="preserve">
|
||||||
|
<value>تمام اتصالات را ببندید</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbProxies" xml:space="preserve">
|
||||||
|
<value>پروکسی</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRulemode" xml:space="preserve">
|
||||||
|
<value>نوع قانون</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeDirect" xml:space="preserve">
|
||||||
|
<value>Direct</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeGlobal" xml:space="preserve">
|
||||||
|
<value>Global</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeNothing" xml:space="preserve">
|
||||||
|
<value>تغییر نده</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeRule" xml:space="preserve">
|
||||||
|
<value>قانون</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesDelaytest" xml:space="preserve">
|
||||||
|
<value>Latency Test</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
||||||
|
<value>Part Node Latency Test</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||||
|
<value>Select active node (Enter)</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -117,11 +117,8 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<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>
|
||||||
<data name="BatchExportSubscriptionSuccessfully" xml:space="preserve">
|
|
||||||
<value>Batch export subscription to clipboard successfully</value>
|
|
||||||
</data>
|
|
||||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||||
<value>Batch export share URL to clipboard successfully</value>
|
<value>Export Share Link to Clipboard Successfully</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CheckServerSettings" xml:space="preserve">
|
<data name="CheckServerSettings" xml:space="preserve">
|
||||||
<value>Please check the server settings first</value>
|
<value>Please check the server settings first</value>
|
||||||
@@ -148,7 +145,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>
|
||||||
@@ -159,9 +156,6 @@
|
|||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>Please fill in the correct format server port</value>
|
<value>Please fill in the correct format server port</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillKcpParameters" xml:space="preserve">
|
|
||||||
<value>Please fill in the KCP parameters correctly</value>
|
|
||||||
</data>
|
|
||||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||||
<value>Please fill in the local listening port</value>
|
<value>Please fill in the local listening port</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -174,14 +168,8 @@
|
|||||||
<data name="FillUUID" xml:space="preserve">
|
<data name="FillUUID" xml:space="preserve">
|
||||||
<value>Please fill in the user ID</value>
|
<value>Please fill in the user ID</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectClientConfiguration" xml:space="preserve">
|
|
||||||
<value> is not the correct client configuration file, please check</value>
|
|
||||||
</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 name="IncorrectServerConfiguration" xml:space="preserve">
|
|
||||||
<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>
|
||||||
@@ -250,13 +238,13 @@
|
|||||||
<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 subscriptions end</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgUpdateSubscriptionStart" xml:space="preserve">
|
<data name="MsgUpdateSubscriptionStart" xml:space="preserve">
|
||||||
<value>Update subscription starts</value>
|
<value>Update subscriptions start</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgUpdateV2rayCoreSuccessfully" xml:space="preserve">
|
<data name="MsgUpdateV2rayCoreSuccessfully" xml:space="preserve">
|
||||||
<value>Update Core successfully</value>
|
<value>Update Core successfully</value>
|
||||||
@@ -267,9 +255,6 @@
|
|||||||
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
||||||
<value>Non-VMess or ss protocol</value>
|
<value>Non-VMess or ss protocol</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NonVmessService" xml:space="preserve">
|
|
||||||
<value> non-standard service, this feature is invalid</value>
|
|
||||||
</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>
|
||||||
</data>
|
</data>
|
||||||
@@ -277,7 +262,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>
|
||||||
@@ -308,13 +293,13 @@
|
|||||||
{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 the shared link successfully</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TestMeOutput" xml:space="preserve">
|
<data name="TestMeOutput" xml:space="preserve">
|
||||||
<value>The ping of current service: {0} ms</value>
|
<value>The ping of current service: {0} ms</value>
|
||||||
@@ -335,13 +320,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>
|
||||||
@@ -359,13 +344,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/splithttp 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>
|
||||||
@@ -374,7 +359,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/splithttp 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>
|
||||||
@@ -398,7 +383,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>
|
||||||
@@ -415,15 +400,9 @@
|
|||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>Please browse to import server configuration</value>
|
<value>Please browse to import server configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SystemProxy" xml:space="preserve">
|
|
||||||
<value>System proxy</value>
|
|
||||||
</data>
|
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>Testing...</value>
|
<value>Testing...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TooManyServersTip" xml:space="preserve">
|
|
||||||
<value>Too many servers, please open the main interface</value>
|
|
||||||
</data>
|
|
||||||
<data name="LabLAN" xml:space="preserve">
|
<data name="LabLAN" xml:space="preserve">
|
||||||
<value>LAN</value>
|
<value>LAN</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -443,13 +422,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>
|
||||||
@@ -458,7 +437,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>
|
||||||
@@ -473,16 +452,16 @@
|
|||||||
<value>Update current subscription with proxy</value>
|
<value>Update current subscription with proxy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSubscription" xml:space="preserve">
|
<data name="menuSubscription" xml:space="preserve">
|
||||||
<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 subscriptions without proxy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSubUpdateViaProxy" xml:space="preserve">
|
<data name="menuSubUpdateViaProxy" xml:space="preserve">
|
||||||
<value>Update subscription with proxy</value>
|
<value>Update subscriptions with proxy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSystemproxy" xml:space="preserve">
|
<data name="menuSystemproxy" xml:space="preserve">
|
||||||
<value>System proxy</value>
|
<value>System proxy</value>
|
||||||
@@ -494,7 +473,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>
|
||||||
@@ -509,10 +488,10 @@
|
|||||||
<value>Follow System Theme</value>
|
<value>Follow System Theme</value>
|
||||||
</data>
|
</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>Importing Share Links from clipboard (Ctrl+V)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddServerViaScan" xml:space="preserve">
|
<data name="menuAddServerViaScan" xml:space="preserve">
|
||||||
<value>Scan QR code on the screen (Ctrl+S)</value>
|
<value>Scan QR code on the screen (Ctrl+S)</value>
|
||||||
@@ -532,9 +511,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>
|
||||||
@@ -547,17 +523,11 @@
|
|||||||
<data name="menuTcpingServer" xml:space="preserve">
|
<data name="menuTcpingServer" xml:space="preserve">
|
||||||
<value>Test servers with tcping (Ctrl+O)</value>
|
<value>Test servers with tcping (Ctrl+O)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTestMe" xml:space="preserve">
|
|
||||||
<value>Test current service status</value>
|
|
||||||
</data>
|
|
||||||
<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 complete configuration</value>
|
||||||
</data>
|
</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 Link to Clipboard (Ctrl+C)</value>
|
||||||
</data>
|
|
||||||
<data name="menuExport2SubContent" xml:space="preserve">
|
|
||||||
<value>Export subscription (base64) share to clipboard</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>Add a custom configuration server</value>
|
<value>Add a custom configuration server</value>
|
||||||
@@ -578,22 +548,19 @@
|
|||||||
<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 name="menuMsgViewFilter" xml:space="preserve">
|
|
||||||
<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>
|
||||||
@@ -608,7 +575,7 @@
|
|||||||
<value>Share</value>
|
<value>Share</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvEnabled" xml:space="preserve">
|
<data name="LvEnabled" xml:space="preserve">
|
||||||
<value>Enabled Update</value>
|
<value>Enable update</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvSort" xml:space="preserve">
|
<data name="LvSort" xml:space="preserve">
|
||||||
<value>Sort</value>
|
<value>Sort</value>
|
||||||
@@ -632,10 +599,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>
|
||||||
@@ -701,10 +668,10 @@
|
|||||||
<value>Encryption</value>
|
<value>Encryption</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPreSocksPort" xml:space="preserve">
|
<data name="TbPreSocksPort" xml:space="preserve">
|
||||||
<value>txtPreSocksPort</value>
|
<value>Socks port</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 sing-box 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>
|
||||||
@@ -755,7 +722,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>
|
||||||
@@ -788,7 +755,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>
|
||||||
@@ -797,7 +764,7 @@
|
|||||||
<value>Enable Statistics (Require restart)</value>
|
<value>Enable Statistics (Require restart)</value>
|
||||||
</data>
|
</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>
|
||||||
@@ -821,10 +788,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>
|
||||||
@@ -836,7 +803,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>
|
||||||
@@ -845,10 +812,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>
|
||||||
@@ -920,13 +887,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>
|
||||||
@@ -935,7 +902,7 @@
|
|||||||
<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 (Delete)</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>
|
||||||
@@ -950,7 +917,7 @@
|
|||||||
<value>Support DnsObject, Click to view the document</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>For group please leave blank here</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipChangeRouting" xml:space="preserve">
|
<data name="TipChangeRouting" xml:space="preserve">
|
||||||
<value>Routing setting is changed</value>
|
<value>Routing setting is changed</value>
|
||||||
@@ -961,6 +928,9 @@
|
|||||||
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
||||||
<value>RouteOnly</value>
|
<value>RouteOnly</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||||
|
<value>Do not use proxy servers for local (intranet) addresses</value>
|
||||||
|
</data>
|
||||||
<data name="menuMixedTestServer" xml:space="preserve">
|
<data name="menuMixedTestServer" xml:space="preserve">
|
||||||
<value>One-click multi test Latency and speed (Ctrl+E)</value>
|
<value>One-click multi test Latency and speed (Ctrl+E)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -980,7 +950,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>
|
||||||
@@ -991,21 +961,9 @@
|
|||||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||||
<value>TunMode settings</value>
|
<value>TunMode settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
|
|
||||||
<value>Direct IP CIDR, separated by commas (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
|
|
||||||
<value>Direct Process name, separated by commas (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
|
|
||||||
<value>Show console</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMoveToGroup" xml:space="preserve">
|
<data name="menuMoveToGroup" xml:space="preserve">
|
||||||
<value>Move to group</value>
|
<value>Move to group</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
|
|
||||||
<value>Custom Template</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||||
<value>Enable Server Drag Drop Sort(Require restart)</value>
|
<value>Enable Server Drag Drop Sort(Require restart)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1040,31 +998,19 @@
|
|||||||
<value>Copy the font TTF/TTC 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 = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6;</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 name="TbSettingsTunModeProxyIP" xml:space="preserve">
|
|
||||||
<value>Proxy IP CIDR, separated by commas (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeProxyProcess" xml:space="preserve">
|
|
||||||
<value>Proxy Process name, separated by commas (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
|
|
||||||
<value>Bypass Mode</value>
|
|
||||||
</data>
|
</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 name="TbSettingsTunModeDNS" xml:space="preserve">
|
|
||||||
<value>DNS object, e.g. {"servers":[]}</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMoveTo" xml:space="preserve">
|
<data name="menuMoveTo" xml:space="preserve">
|
||||||
<value>Move up and down</value>
|
<value>Move up and down</value>
|
||||||
@@ -1082,7 +1028,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>
|
||||||
@@ -1091,16 +1037,16 @@
|
|||||||
<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>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
|
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
|
||||||
<value>Enable logging to file</value>
|
<value>Enable logging to file</value>
|
||||||
@@ -1139,7 +1085,7 @@
|
|||||||
<value>Domain</value>
|
<value>Domain</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddHysteria2Server" xml:space="preserve">
|
<data name="menuAddHysteria2Server" xml:space="preserve">
|
||||||
<value>Add [Trojan] server</value>
|
<value>Add [Hysteria2] server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
||||||
<value>Hysteria Max bandwidth (Up/Dw)</value>
|
<value>Hysteria Max bandwidth (Up/Dw)</value>
|
||||||
@@ -1147,4 +1093,190 @@
|
|||||||
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
|
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
|
||||||
<value>Use System Hosts</value>
|
<value>Use System Hosts</value>
|
||||||
</data>
|
</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>
|
||||||
|
<data name="TbSorting" xml:space="preserve">
|
||||||
|
<value>Sorting</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingChain" xml:space="preserve">
|
||||||
|
<value>Chain</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDefault" xml:space="preserve">
|
||||||
|
<value>Default</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDelay" xml:space="preserve">
|
||||||
|
<value>Delay</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDownSpeed" xml:space="preserve">
|
||||||
|
<value>Download Speed</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingDownTraffic" xml:space="preserve">
|
||||||
|
<value>Download Traffic</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingHost" xml:space="preserve">
|
||||||
|
<value>Host</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingName" xml:space="preserve">
|
||||||
|
<value>Name</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingNetwork" xml:space="preserve">
|
||||||
|
<value>Network</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingTime" xml:space="preserve">
|
||||||
|
<value>Time</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingType" xml:space="preserve">
|
||||||
|
<value>Type</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingUpSpeed" xml:space="preserve">
|
||||||
|
<value>Upload Speed</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSortingUpTraffic" xml:space="preserve">
|
||||||
|
<value>Upload Traffic</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbConnections" xml:space="preserve">
|
||||||
|
<value>Connections</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuConnectionClose" xml:space="preserve">
|
||||||
|
<value>Close Connection</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuConnectionCloseAll" xml:space="preserve">
|
||||||
|
<value>Close All Connection</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbProxies" xml:space="preserve">
|
||||||
|
<value>Proxies</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRulemode" xml:space="preserve">
|
||||||
|
<value>Rule mode</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeDirect" xml:space="preserve">
|
||||||
|
<value>Direct</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeGlobal" xml:space="preserve">
|
||||||
|
<value>Global</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeNothing" xml:space="preserve">
|
||||||
|
<value>Do not change</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuModeRule" xml:space="preserve">
|
||||||
|
<value>Rule</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesDelaytest" xml:space="preserve">
|
||||||
|
<value>Latency Test</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
||||||
|
<value>Part Node Latency Test</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesReload" xml:space="preserve">
|
||||||
|
<value>Refresh Proxies</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||||
|
<value>Select active node (Enter)</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
|
||||||
|
<value>Default domain strategy for outbound</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||||
|
<value>Multi-Server lowest latency</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
|
||||||
|
<value>Main layout orientation(Require restart)</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
|
||||||
|
<value>Multi-server load balancing</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
|
||||||
|
<value>Outbound DNS address</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuProfileAutofitColumnWidth" xml:space="preserve">
|
||||||
|
<value>Auto column width adjustment</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
|
||||||
|
<value>Export Base64-encoded Share Links to Clipboard</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
||||||
|
<value>Export selected server for complete configuration to clipboard</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
||||||
|
<value>Show or hide the main window</value>
|
||||||
|
</data>
|
||||||
|
<data name="UpdateStandalonePackageTip" xml:space="preserve">
|
||||||
|
<value>You are currently running a standalone package, please manually download the SelfContained.7z file to unzip and overwrite it!</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
|
<value>Custom config socks port</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -117,9 +117,6 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<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>
|
||||||
<data name="BatchExportSubscriptionSuccessfully" xml:space="preserve">
|
|
||||||
<value>Экспортирование подписок в буфер обмена успешно завершено</value>
|
|
||||||
</data>
|
|
||||||
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
<data name="BatchExportURLSuccessfully" xml:space="preserve">
|
||||||
<value>Экспортирование URL в буфер обмена успешно завершено</value>
|
<value>Экспортирование URL в буфер обмена успешно завершено</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -159,9 +156,6 @@
|
|||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>Пожалуйста, укажите порт сервера в правильном формате</value>
|
<value>Пожалуйста, укажите порт сервера в правильном формате</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillKcpParameters" xml:space="preserve">
|
|
||||||
<value>Пожалуйста, заполните параметры KCP корректно</value>
|
|
||||||
</data>
|
|
||||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||||
<value>Пожалуйста, укажите локальный порт прослушивания</value>
|
<value>Пожалуйста, укажите локальный порт прослушивания</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -174,15 +168,9 @@
|
|||||||
<data name="FillUUID" xml:space="preserve">
|
<data name="FillUUID" xml:space="preserve">
|
||||||
<value>Пожалуйста, заполните идентификатор пользователя</value>
|
<value>Пожалуйста, заполните идентификатор пользователя</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectClientConfiguration" xml:space="preserve">
|
|
||||||
<value>Некорректный файл конфигурации клиента, пожалуйста, проверьте</value>
|
|
||||||
</data>
|
|
||||||
<data name="Incorrectconfiguration" xml:space="preserve">
|
<data name="Incorrectconfiguration" xml:space="preserve">
|
||||||
<value>Некорректная конфигурация, пожалуйста, проверьте</value>
|
<value>Некорректная конфигурация, пожалуйста, проверьте</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IncorrectServerConfiguration" xml:space="preserve">
|
|
||||||
<value>Некорректный файл конфигурации сервера, пожалуйста, проверьте</value>
|
|
||||||
</data>
|
|
||||||
<data name="InitialConfiguration" xml:space="preserve">
|
<data name="InitialConfiguration" xml:space="preserve">
|
||||||
<value>Исходная конфигурация</value>
|
<value>Исходная конфигурация</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -267,9 +255,6 @@
|
|||||||
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
<data name="NonvmessOrssProtocol" xml:space="preserve">
|
||||||
<value>Не является протоколом Vmess или SS</value>
|
<value>Не является протоколом Vmess или SS</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NonVmessService" xml:space="preserve">
|
|
||||||
<value> нестандартный сервис, эта функция недействительна</value>
|
|
||||||
</data>
|
|
||||||
<data name="NotFoundCore" xml:space="preserve">
|
<data name="NotFoundCore" xml:space="preserve">
|
||||||
<value>Файл Core (имя файла: {1}) не найден в папке ({0}), загрузите и поместите его в папку, адрес загрузки: {2}</value>
|
<value>Файл Core (имя файла: {1}) не найден в папке ({0}), загрузите и поместите его в папку, адрес загрузки: {2}</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -415,15 +400,9 @@
|
|||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>Пожалуйста, просмотрите, чтобы импортировать конфигурацию сервера</value>
|
<value>Пожалуйста, просмотрите, чтобы импортировать конфигурацию сервера</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SystemProxy" xml:space="preserve">
|
|
||||||
<value>Системный прокси</value>
|
|
||||||
</data>
|
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>Тестирование...</value>
|
<value>Тестирование...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TooManyServersTip" xml:space="preserve">
|
|
||||||
<value>Слишком много серверов, пожалуйста, откройте главный интерфейс</value>
|
|
||||||
</data>
|
|
||||||
<data name="LabLAN" xml:space="preserve">
|
<data name="LabLAN" xml:space="preserve">
|
||||||
<value>LAN</value>
|
<value>LAN</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -532,9 +511,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>
|
||||||
@@ -547,18 +523,12 @@
|
|||||||
<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">
|
|
||||||
<value>Проверить текущий статус службы</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>Экспортировать выбранный сервер для клиента</value>
|
<value>Экспортировать выбранный сервер для клиента</value>
|
||||||
</data>
|
</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>
|
||||||
<data name="menuExport2SubContent" xml:space="preserve">
|
|
||||||
<value>Экспортировать ссылку-подписку (base64) в буфер обмена</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>Добавить сервер пользовательской конфигурации</value>
|
<value>Добавить сервер пользовательской конфигурации</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -589,9 +559,6 @@
|
|||||||
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
<data name="menuMsgViewCopyAll" xml:space="preserve">
|
||||||
<value>Скопировать все</value>
|
<value>Скопировать все</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuMsgViewFilter" xml:space="preserve">
|
|
||||||
<value>Установить фильтры сообщений</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
<data name="menuMsgViewSelectAll" xml:space="preserve">
|
||||||
<value>Выбрать все (Ctrl+A)</value>
|
<value>Выбрать все (Ctrl+A)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -704,7 +671,7 @@
|
|||||||
<value>txtPreSocksPort</value>
|
<value>txtPreSocksPort</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TipPreSocksPort" xml:space="preserve">
|
<data name="TipPreSocksPort" xml:space="preserve">
|
||||||
<value>* После установки этого значения служба socks будет запущена с использованием sing-box для обеспечения таких функций, как отображение скорости</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>
|
||||||
@@ -967,6 +934,9 @@
|
|||||||
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
<data name="TbSettingsRouteOnly" xml:space="preserve">
|
||||||
<value>Только маршрут</value>
|
<value>Только маршрут</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
|
||||||
|
<value>Не используйте прокси-серверы для локальных (интранет) адресов</value>
|
||||||
|
</data>
|
||||||
<data name="menuMixedTestServer" xml:space="preserve">
|
<data name="menuMixedTestServer" xml:space="preserve">
|
||||||
<value>Тест задержки и скорости всех серверов (Ctrl+E)</value>
|
<value>Тест задержки и скорости всех серверов (Ctrl+E)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -997,21 +967,9 @@
|
|||||||
<data name="TbSettingsTunMode" xml:space="preserve">
|
<data name="TbSettingsTunMode" xml:space="preserve">
|
||||||
<value>Настройки TunMode</value>
|
<value>Настройки TunMode</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
|
|
||||||
<value>Прямой IP CIDR, разделенный запятыми (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
|
|
||||||
<value>Имя процесса, разделенное запятыми (,)</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
|
|
||||||
<value>Показать консоль</value>
|
|
||||||
</data>
|
|
||||||
<data name="menuMoveToGroup" xml:space="preserve">
|
<data name="menuMoveToGroup" xml:space="preserve">
|
||||||
<value>Перейти в группу</value>
|
<value>Перейти в группу</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
|
|
||||||
<value>Пользовательский шаблон</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||||
<value>Включить сортировку перетаскиванием сервера (требуется перезагрузка)</value>
|
<value>Включить сортировку перетаскиванием сервера (требуется перезагрузка)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1045,9 +1003,6 @@
|
|||||||
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
|
||||||
<value>Скопируйте файл шрифта TTF/TTC в каталог guiFonts, перезапустите настройки</value>
|
<value>Скопируйте файл шрифта TTF/TTC в каталог guiFonts, перезапустите настройки</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSocksPortTip" xml:space="preserve">
|
|
||||||
<value>HTTP port=socks port+1</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
<data name="TbSettingsStartBootTip" xml:space="preserve">
|
||||||
<value>Установите это с правами администратора</value>
|
<value>Установите это с правами администратора</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1072,4 +1027,4 @@
|
|||||||
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
|
||||||
<value>URL спидтеста</value>
|
<value>URL спидтеста</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user