Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4859dcda08 | ||
|
|
2e962e555d | ||
|
|
ab73e5acb2 | ||
|
|
4e3e5ce130 | ||
|
|
bb8eef3bf5 | ||
|
|
eee87ded29 | ||
|
|
e0f005bd96 | ||
|
|
2cacc372ad | ||
|
|
0b1b681655 | ||
|
|
deafd73306 | ||
|
|
317a5da120 | ||
|
|
071cefc511 | ||
|
|
32a5cc8aa3 | ||
|
|
c41378a085 | ||
|
|
6910e03ef4 | ||
|
|
5060a358db | ||
|
|
b3e9a957c4 | ||
|
|
f6dbfc2dac | ||
|
|
2966a34e63 | ||
|
|
50959951ae | ||
|
|
c2e1cf7bdb | ||
|
|
51ac7cc8be | ||
|
|
3144f1d1c2 | ||
|
|
a176e7b912 | ||
|
|
1198ec0f74 | ||
|
|
4104964e38 | ||
|
|
3bbd1edf06 | ||
|
|
41cc260b5c | ||
|
|
6cd5063c9b | ||
|
|
e544df6d01 | ||
|
|
f952d2383c | ||
|
|
8a29e147d3 | ||
|
|
8a19128e7f | ||
|
|
7dc9fbd8ff | ||
|
|
31a179e647 |
8
.github/workflows/build-linux.yml
vendored
8
.github/workflows/build-linux.yml
vendored
@@ -36,10 +36,10 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cd v2rayN
|
cd v2rayN
|
||||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-x64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPath64
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-x64 --self-contained=true -o $OutputPath64
|
||||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-arm64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPathArm64
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-arm64 --self-contained=true -o $OutputPathArm64
|
||||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-x64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPath64
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-x64 --self-contained=true -p:PublishTrimmed=true -o $OutputPath64
|
||||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPathArm64
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4.6.0
|
uses: actions/upload-artifact@v4.6.0
|
||||||
|
|||||||
8
.github/workflows/build-osx.yml
vendored
8
.github/workflows/build-osx.yml
vendored
@@ -36,10 +36,10 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cd v2rayN
|
cd v2rayN
|
||||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPath64
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained=true -o $OutputPath64
|
||||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPathArm64
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained=true -o $OutputPathArm64
|
||||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-x64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPath64
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-x64 --self-contained=true -p:PublishTrimmed=true -o $OutputPath64
|
||||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPathArm64
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4.6.0
|
uses: actions/upload-artifact@v4.6.0
|
||||||
|
|||||||
28
.github/workflows/build-windows-desktop.yml
vendored
28
.github/workflows/build-windows-desktop.yml
vendored
@@ -36,10 +36,10 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cd v2rayN
|
cd v2rayN
|
||||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-x64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPath64
|
||||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-arm64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
|
||||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -p:EnableWindowsTargeting=true -o $OutputPath64
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64
|
||||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4.6.0
|
uses: actions/upload-artifact@v4.6.0
|
||||||
@@ -47,4 +47,22 @@ jobs:
|
|||||||
name: v2rayN-windows-desktop
|
name: v2rayN-windows-desktop
|
||||||
path: |
|
path: |
|
||||||
${{ github.workspace }}/v2rayN/Release/windows*
|
${{ github.workspace }}/v2rayN/Release/windows*
|
||||||
|
|
||||||
|
# release zip archive
|
||||||
|
- name: Package release zip archive
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
run: |
|
||||||
|
chmod 755 package-release-zip.sh
|
||||||
|
./package-release-zip.sh $OutputArch $OutputPath64
|
||||||
|
mv "v2rayN-${OutputArch}.zip" "v2rayN-${OutputArch}-desktop.zip"
|
||||||
|
./package-release-zip.sh $OutputArchArm $OutputPathArm64
|
||||||
|
mv "v2rayN-${OutputArchArm}.zip" "v2rayN-${OutputArchArm}-desktop.zip"
|
||||||
|
|
||||||
|
- name: Upload zip archive to release
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
with:
|
||||||
|
file: ${{ github.workspace }}/v2rayN*.zip
|
||||||
|
tag: ${{ github.event.inputs.release_tag }}
|
||||||
|
file_glob: true
|
||||||
|
prerelease: true
|
||||||
|
|||||||
12
.github/workflows/build-windows.yml
vendored
12
.github/workflows/build-windows.yml
vendored
@@ -37,12 +37,12 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cd v2rayN
|
cd v2rayN
|
||||||
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained=false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64
|
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPath64
|
||||||
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 --self-contained=false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
|
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64
|
||||||
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc
|
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc
|
||||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPath64
|
||||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64
|
||||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64Sc
|
||||||
|
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.8.1</Version>
|
<Version>7.9.2</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@@ -28,6 +28,6 @@
|
|||||||
|
|
||||||
<UseSystemResourceKeys>true</UseSystemResourceKeys>
|
<UseSystemResourceKeys>true</UseSystemResourceKeys>
|
||||||
<PublishSingleFile>true</PublishSingleFile>
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
<PublishReadyToRun>false</PublishReadyToRun>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.3" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.4" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.2.3" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.2.4" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.3" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.4" />
|
||||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.3" />
|
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.4" />
|
||||||
<PackageVersion Include="CliWrap" Version="3.7.1" />
|
<PackageVersion Include="CliWrap" Version="3.8.0" />
|
||||||
<PackageVersion Include="Downloader" Version="3.3.3" />
|
<PackageVersion Include="Downloader" Version="3.3.3" />
|
||||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.2.0" />
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.2.0" />
|
||||||
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
|
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
|
||||||
|
|||||||
@@ -86,17 +86,43 @@ public static class ProcUtils
|
|||||||
GetProcessKeyInfo(proc, review, out var procId, out var fileName, out var processName);
|
GetProcessKeyInfo(proc, review, out var procId, out var fileName, out var processName);
|
||||||
|
|
||||||
try
|
try
|
||||||
{ proc?.Kill(true); }
|
{
|
||||||
catch (Exception ex) { Logging.SaveLog(_tag, ex); }
|
if (Utils.IsNonWindows())
|
||||||
|
{
|
||||||
|
proc?.Kill(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{ proc?.Kill(); }
|
{
|
||||||
catch (Exception ex) { Logging.SaveLog(_tag, ex); }
|
proc?.Kill();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{ proc?.Close(); }
|
{
|
||||||
catch (Exception ex) { Logging.SaveLog(_tag, ex); }
|
proc?.Close();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{ proc?.Dispose(); }
|
{
|
||||||
catch (Exception ex) { Logging.SaveLog(_tag, ex); }
|
proc?.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
await Task.Delay(300);
|
await Task.Delay(300);
|
||||||
await ProcessKillByKeyInfo(review, procId, fileName, processName);
|
await ProcessKillByKeyInfo(review, procId, fileName, processName);
|
||||||
|
|||||||
@@ -433,10 +433,22 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var ipProperties = IPGlobalProperties.GetIPGlobalProperties();
|
List<IPEndPoint> lstIpEndPoints = new();
|
||||||
var ipEndPoints = ipProperties.GetActiveTcpListeners();
|
List<TcpConnectionInformation> lstTcpConns = new();
|
||||||
//var lstIpEndPoints = new List<IPEndPoint>(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
|
||||||
return ipEndPoints.Any(endPoint => endPoint.Port == port);
|
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
||||||
|
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
|
||||||
|
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
|
||||||
|
|
||||||
|
if (lstIpEndPoints?.FindIndex(it => it.Port == port) >= 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstTcpConns?.FindIndex(it => it.LocalEndPoint.Port == port) >= 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -786,6 +798,24 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetBinConfigPath(string filename = "")
|
||||||
|
{
|
||||||
|
var tempPath = Path.Combine(StartupPath(), "binConfigs");
|
||||||
|
if (!Directory.Exists(tempPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(tempPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utils.IsNullOrEmpty(filename))
|
||||||
|
{
|
||||||
|
return tempPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Path.Combine(tempPath, filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion TempPath
|
#endregion TempPath
|
||||||
|
|
||||||
#region Platform
|
#region Platform
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums
|
||||||
{
|
{
|
||||||
public enum EMsgCommand
|
public enum EMsgCommand
|
||||||
{
|
{
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
SendMsgView,
|
SendMsgView,
|
||||||
SendSnackMsg,
|
SendSnackMsg,
|
||||||
RefreshProfiles,
|
RefreshProfiles,
|
||||||
StopSpeedtest,
|
|
||||||
AppExit
|
AppExit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace ServiceLib
|
|||||||
public const string ConfigFileName = "guiNConfig.json";
|
public const string ConfigFileName = "guiNConfig.json";
|
||||||
public const string CoreConfigFileName = "config.json";
|
public const string CoreConfigFileName = "config.json";
|
||||||
public const string CorePreConfigFileName = "configPre.json";
|
public const string CorePreConfigFileName = "configPre.json";
|
||||||
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
|
public const string CoreSpeedtestConfigFileName = "configTest{0}.json";
|
||||||
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
|
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
|
||||||
public const string ClashMixinConfigFileName = "Mixin.yaml";
|
public const string ClashMixinConfigFileName = "Mixin.yaml";
|
||||||
|
|
||||||
@@ -64,8 +64,6 @@ namespace ServiceLib
|
|||||||
public const string GrpcGunMode = "gun";
|
public const string GrpcGunMode = "gun";
|
||||||
public const string GrpcMultiMode = "multi";
|
public const string GrpcMultiMode = "multi";
|
||||||
public const int MaxPort = 65536;
|
public const int MaxPort = 65536;
|
||||||
public const string DelayUnit = "";
|
|
||||||
public const string SpeedUnit = "";
|
|
||||||
public const int MinFontSize = 8;
|
public const int MinFontSize = 8;
|
||||||
public const string RebootAs = "rebootas";
|
public const string RebootAs = "rebootas";
|
||||||
public const string AvaAssets = "avares://v2rayN/Assets/";
|
public const string AvaAssets = "avares://v2rayN/Assets/";
|
||||||
@@ -105,10 +103,10 @@ namespace ServiceLib
|
|||||||
|
|
||||||
public static readonly List<string> SpeedTestUrls =
|
public static readonly List<string> SpeedTestUrls =
|
||||||
[
|
[
|
||||||
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
@"https://cachefly.cachefly.net/50mb.test",
|
||||||
@"https://speed.cloudflare.com/__down?bytes=50000000",
|
|
||||||
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
||||||
@"https://cachefly.cachefly.net/50mb.test"
|
@"https://speed.cloudflare.com/__down?bytes=50000000",
|
||||||
|
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SpeedPingTestUrls =
|
public static readonly List<string> SpeedPingTestUrls =
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
public sealed class AppHandler
|
public sealed class AppHandler
|
||||||
{
|
{
|
||||||
@@ -98,6 +98,7 @@
|
|||||||
{
|
{
|
||||||
FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1));
|
FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1));
|
||||||
FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1));
|
FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1));
|
||||||
|
FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,4 +253,4 @@
|
|||||||
|
|
||||||
#endregion Core Type
|
#endregion Core Type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using static ServiceLib.Models.ClashProxies;
|
using static ServiceLib.Models.ClashProxies;
|
||||||
|
|
||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
@@ -38,63 +38,63 @@ namespace ServiceLib.Handler
|
|||||||
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> updateFunc)
|
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> updateFunc)
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
|
||||||
if (blAll)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 5; i++)
|
if (blAll)
|
||||||
{
|
{
|
||||||
if (_proxies != null)
|
for (var i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
break;
|
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(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Task.Delay(5000).Wait();
|
|
||||||
}
|
}
|
||||||
if (_proxies == null)
|
|
||||||
|
if (lstProxy == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lstProxy = new List<ClashProxyModel>();
|
var urlBase = $"{GetApiUrl()}/proxies";
|
||||||
foreach (KeyValuePair<string, ProxiesItem> kv in _proxies)
|
urlBase += @"/{0}/delay?timeout=10000&url=" + AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl;
|
||||||
|
|
||||||
|
var tasks = new List<Task>();
|
||||||
|
foreach (var it in lstProxy)
|
||||||
{
|
{
|
||||||
if (Global.notAllowTestType.Contains(kv.Value.type.ToLower()))
|
if (Global.notAllowTestType.Contains(it.Type.ToLower()))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
lstProxy.Add(new ClashProxyModel()
|
var name = it.Name;
|
||||||
|
var url = string.Format(urlBase, name);
|
||||||
|
tasks.Add(Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Name = kv.Value.name,
|
var result = await HttpClientHelper.Instance.TryGetAsync(url);
|
||||||
Type = kv.Value.type.ToLower(),
|
updateFunc?.Invoke(it, result);
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
}
|
Task.WaitAll(tasks.ToArray());
|
||||||
|
|
||||||
if (lstProxy == null)
|
Task.Delay(1000).Wait();
|
||||||
{
|
updateFunc?.Invoke(null, "");
|
||||||
return;
|
});
|
||||||
}
|
|
||||||
var urlBase = $"{GetApiUrl()}/proxies";
|
|
||||||
urlBase += @"/{0}/delay?timeout=10000&url=" + AppHandler.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);
|
|
||||||
updateFunc?.Invoke(it, result);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
Task.WaitAll(tasks.ToArray());
|
|
||||||
|
|
||||||
Task.Delay(1000).Wait();
|
|
||||||
updateFunc?.Invoke(null, "");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ProxiesItem>? GetClashProxyGroups()
|
public List<ProxiesItem>? GetClashProxyGroups()
|
||||||
@@ -120,7 +120,7 @@ namespace ServiceLib.Handler
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var url = $"{GetApiUrl()}/proxies/{name}";
|
var url = $"{GetApiUrl()}/proxies/{name}";
|
||||||
Dictionary<string, string> headers = new Dictionary<string, string>();
|
var headers = new Dictionary<string, string>();
|
||||||
headers.Add("name", nameNode);
|
headers.Add("name", nameNode);
|
||||||
await HttpClientHelper.Instance.PutAsync(url, headers);
|
await HttpClientHelper.Instance.PutAsync(url, headers);
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ namespace ServiceLib.Handler
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var url = $"{GetApiUrl()}/configs?force=true";
|
var url = $"{GetApiUrl()}/configs?force=true";
|
||||||
Dictionary<string, string> headers = new Dictionary<string, string>();
|
var headers = new Dictionary<string, string>();
|
||||||
headers.Add("path", filePath);
|
headers.Add("path", filePath);
|
||||||
await HttpClientHelper.Instance.PutAsync(url, headers);
|
await HttpClientHelper.Instance.PutAsync(url, headers);
|
||||||
}
|
}
|
||||||
@@ -194,4 +194,4 @@ namespace ServiceLib.Handler
|
|||||||
return $"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort2}";
|
return $"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort2}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,6 +125,10 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrl;
|
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrl;
|
||||||
}
|
}
|
||||||
|
if (config.SpeedTestItem.MixedConcurrencyCount < 1)
|
||||||
|
{
|
||||||
|
config.SpeedTestItem.MixedConcurrencyCount = 5;
|
||||||
|
}
|
||||||
|
|
||||||
config.Mux4RayItem ??= new()
|
config.Mux4RayItem ??= new()
|
||||||
{
|
{
|
||||||
@@ -290,7 +294,7 @@ namespace ServiceLib.Handler
|
|||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <param name="indexes"></param>
|
/// <param name="indexes"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<int> RemoveServer(Config config, List<ProfileItem> indexes)
|
public static async Task<int> RemoveServers(Config config, List<ProfileItem> indexes)
|
||||||
{
|
{
|
||||||
var subid = "TempRemoveSubId";
|
var subid = "TempRemoveSubId";
|
||||||
foreach (var item in indexes)
|
foreach (var item in indexes)
|
||||||
@@ -299,7 +303,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
await SQLiteHelper.Instance.UpdateAllAsync(indexes);
|
await SQLiteHelper.Instance.UpdateAllAsync(indexes);
|
||||||
await RemoveServerViaSubid(config, subid, false);
|
await RemoveServersViaSubid(config, subid, false);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -754,9 +758,9 @@ namespace ServiceLib.Handler
|
|||||||
Security = t.Security,
|
Security = t.Security,
|
||||||
Network = t.Network,
|
Network = t.Network,
|
||||||
StreamSecurity = t.StreamSecurity,
|
StreamSecurity = t.StreamSecurity,
|
||||||
Delay = t33 == null ? 0 : t33.Delay,
|
Delay = t33?.Delay ?? 0,
|
||||||
Speed = t33 == null ? 0 : t33.Speed,
|
Speed = t33?.Speed ?? 0,
|
||||||
Sort = t33 == null ? 0 : t33.Sort
|
Sort = t33?.Sort ?? 0
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
Enum.TryParse(colName, true, out EServerColName name);
|
Enum.TryParse(colName, true, out EServerColName name);
|
||||||
@@ -882,7 +886,7 @@ namespace ServiceLib.Handler
|
|||||||
lstRemove.Add(item);
|
lstRemove.Add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await RemoveServer(config, lstRemove);
|
await RemoveServers(config, lstRemove);
|
||||||
|
|
||||||
return new Tuple<int, int>(lstProfile.Count, lstKeep.Count);
|
return new Tuple<int, int>(lstProfile.Count, lstKeep.Count);
|
||||||
}
|
}
|
||||||
@@ -1047,6 +1051,24 @@ namespace ServiceLib.Handler
|
|||||||
return itemSocks;
|
return itemSocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<int> RemoveInvalidServerResult(Config config, string subid)
|
||||||
|
{
|
||||||
|
var lstModel = await AppHandler.Instance.ProfileItems(subid, "");
|
||||||
|
if (lstModel is { Count: <= 0 })
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
var lstProfileExs = await ProfileExHandler.Instance.GetProfileExs();
|
||||||
|
var lstProfile = (from t in lstModel
|
||||||
|
join t2 in lstProfileExs on t.IndexId equals t2.IndexId
|
||||||
|
where t2.Delay == -1
|
||||||
|
select t).ToList();
|
||||||
|
|
||||||
|
await RemoveServers(config, JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstProfile)));
|
||||||
|
|
||||||
|
return lstProfile.Count;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Server
|
#endregion Server
|
||||||
|
|
||||||
#region Batch add servers
|
#region Batch add servers
|
||||||
@@ -1069,7 +1091,7 @@ namespace ServiceLib.Handler
|
|||||||
//remove sub items
|
//remove sub items
|
||||||
if (isSub && Utils.IsNotEmpty(subid))
|
if (isSub && Utils.IsNotEmpty(subid))
|
||||||
{
|
{
|
||||||
await RemoveServerViaSubid(config, subid, isSub);
|
await RemoveServersViaSubid(config, subid, isSub);
|
||||||
subFilter = (await AppHandler.Instance.GetSubItem(subid))?.Filter ?? "";
|
subFilter = (await AppHandler.Instance.GetSubItem(subid))?.Filter ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1163,7 +1185,7 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
if (isSub && Utils.IsNotEmpty(subid))
|
if (isSub && Utils.IsNotEmpty(subid))
|
||||||
{
|
{
|
||||||
await RemoveServerViaSubid(config, subid, isSub);
|
await RemoveServersViaSubid(config, subid, isSub);
|
||||||
}
|
}
|
||||||
int count = 0;
|
int count = 0;
|
||||||
foreach (var it in lstProfiles)
|
foreach (var it in lstProfiles)
|
||||||
@@ -1219,7 +1241,7 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
if (isSub && Utils.IsNotEmpty(subid))
|
if (isSub && Utils.IsNotEmpty(subid))
|
||||||
{
|
{
|
||||||
await RemoveServerViaSubid(config, subid, isSub);
|
await RemoveServersViaSubid(config, subid, isSub);
|
||||||
}
|
}
|
||||||
|
|
||||||
profileItem.Subid = subid;
|
profileItem.Subid = subid;
|
||||||
@@ -1244,7 +1266,7 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
if (isSub && Utils.IsNotEmpty(subid))
|
if (isSub && Utils.IsNotEmpty(subid))
|
||||||
{
|
{
|
||||||
await RemoveServerViaSubid(config, subid, isSub);
|
await RemoveServersViaSubid(config, subid, isSub);
|
||||||
}
|
}
|
||||||
|
|
||||||
var lstSsServer = ShadowsocksFmt.ResolveSip008(strData);
|
var lstSsServer = ShadowsocksFmt.ResolveSip008(strData);
|
||||||
@@ -1431,7 +1453,7 @@ namespace ServiceLib.Handler
|
|||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <param name="subid"></param>
|
/// <param name="subid"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<int> RemoveServerViaSubid(Config config, string subid, bool isSub)
|
public static async Task<int> RemoveServersViaSubid(Config config, string subid, bool isSub)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(subid))
|
if (Utils.IsNullOrEmpty(subid))
|
||||||
{
|
{
|
||||||
@@ -1462,7 +1484,7 @@ namespace ServiceLib.Handler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
await SQLiteHelper.Instance.DeleteAsync(item);
|
await SQLiteHelper.Instance.DeleteAsync(item);
|
||||||
await RemoveServerViaSubid(config, id, false);
|
await RemoveServersViaSubid(config, id, false);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Core configuration file processing class
|
/// Core configuration file processing class
|
||||||
@@ -109,6 +109,30 @@
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<RetResult> GenerateClientSpeedtestConfig(Config config, ProfileItem node, ServerTestItem testItem, string fileName)
|
||||||
|
{
|
||||||
|
var result = new RetResult();
|
||||||
|
var initPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
|
||||||
|
var port = Utils.GetFreePort(initPort + testItem.QueueNum);
|
||||||
|
testItem.Port = port;
|
||||||
|
|
||||||
|
if (AppHandler.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box)
|
||||||
|
{
|
||||||
|
result = await new CoreConfigSingboxService(config).GenerateClientSpeedtestConfig(node, port);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = await new CoreConfigV2rayService(config).GenerateClientSpeedtestConfig(node, port);
|
||||||
|
}
|
||||||
|
if (result.Success != true)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
await File.WriteAllTextAsync(fileName, result.Data.ToString());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<RetResult> GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType)
|
public static async Task<RetResult> GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType)
|
||||||
{
|
{
|
||||||
var result = new RetResult();
|
var result = new RetResult();
|
||||||
@@ -129,4 +153,4 @@
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ namespace ServiceLib.Handler
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
|
var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName);
|
||||||
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
|
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
|
||||||
if (result.Success != true)
|
if (result.Success != true)
|
||||||
{
|
{
|
||||||
@@ -101,7 +101,8 @@ namespace ServiceLib.Handler
|
|||||||
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
||||||
{
|
{
|
||||||
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
|
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
var configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
|
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
|
||||||
|
var configPath = Utils.GetBinConfigPath(fileName);
|
||||||
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
||||||
UpdateFunc(false, result.Msg);
|
UpdateFunc(false, result.Msg);
|
||||||
if (result.Success != true)
|
if (result.Success != true)
|
||||||
@@ -113,7 +114,34 @@ namespace ServiceLib.Handler
|
|||||||
UpdateFunc(false, configPath);
|
UpdateFunc(false, configPath);
|
||||||
|
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
||||||
var proc = await RunProcess(coreInfo, Global.CoreSpeedtestConfigFileName, true, false);
|
var proc = await RunProcess(coreInfo, fileName, true, false);
|
||||||
|
if (proc is null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return proc.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> LoadCoreConfigSpeedtest(ServerTestItem testItem)
|
||||||
|
{
|
||||||
|
var node = await AppHandler.Instance.GetProfileItem(testItem.IndexId);
|
||||||
|
if (node is null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
|
||||||
|
var configPath = Utils.GetBinConfigPath(fileName);
|
||||||
|
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, node, testItem, configPath);
|
||||||
|
if (result.Success != true)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
|
||||||
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
||||||
|
var proc = await RunProcess(coreInfo, fileName, true, false);
|
||||||
if (proc is null)
|
if (proc is null)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
@@ -175,7 +203,7 @@ namespace ServiceLib.Handler
|
|||||||
if (itemSocks != null)
|
if (itemSocks != null)
|
||||||
{
|
{
|
||||||
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
|
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
|
||||||
var fileName = Utils.GetConfigPath(Global.CorePreConfigFileName);
|
var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName);
|
||||||
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
|
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
|
||||||
if (result.Success)
|
if (result.Success)
|
||||||
{
|
{
|
||||||
@@ -225,8 +253,8 @@ namespace ServiceLib.Handler
|
|||||||
StartInfo = new()
|
StartInfo = new()
|
||||||
{
|
{
|
||||||
FileName = fileName,
|
FileName = fileName,
|
||||||
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetConfigPath(configPath) : configPath),
|
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath) : configPath),
|
||||||
WorkingDirectory = Utils.GetConfigPath(),
|
WorkingDirectory = Utils.GetBinConfigPath(),
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
RedirectStandardOutput = displayLog,
|
RedirectStandardOutput = displayLog,
|
||||||
RedirectStandardError = displayLog,
|
RedirectStandardError = displayLog,
|
||||||
@@ -298,7 +326,7 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath)
|
private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath)
|
||||||
{
|
{
|
||||||
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath).AppendQuotes())}";
|
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
|
||||||
|
|
||||||
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
|
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
|
||||||
proc.StartInfo.FileName = shFilePath;
|
proc.StartInfo.FileName = shFilePath;
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace ServiceLib.Handler
|
|||||||
new CoreInfo
|
new CoreInfo
|
||||||
{
|
{
|
||||||
CoreType = ECoreType.v2fly,
|
CoreType = ECoreType.v2fly,
|
||||||
CoreExes = ["wv2ray", "v2ray"],
|
CoreExes = ["v2ray"],
|
||||||
Arguments = "{0}",
|
Arguments = "{0}",
|
||||||
Url = GetCoreUrl(ECoreType.v2fly),
|
Url = GetCoreUrl(ECoreType.v2fly),
|
||||||
Match = "V2Ray",
|
Match = "V2Ray",
|
||||||
@@ -95,7 +95,7 @@ namespace ServiceLib.Handler
|
|||||||
new CoreInfo
|
new CoreInfo
|
||||||
{
|
{
|
||||||
CoreType = ECoreType.Xray,
|
CoreType = ECoreType.Xray,
|
||||||
CoreExes = ["wxray","xray"],
|
CoreExes = ["xray"],
|
||||||
Arguments = "run -c {0}",
|
Arguments = "run -c {0}",
|
||||||
Url = GetCoreUrl(ECoreType.Xray),
|
Url = GetCoreUrl(ECoreType.Xray),
|
||||||
ReleaseApiUrl = urlXray.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
ReleaseApiUrl = urlXray.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
//using System.Reactive.Linq;
|
//using System.Reactive.Linq;
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
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 readonly Queue<string> _queIndexIds = new();
|
||||||
public static ProfileExHandler Instance => _instance.Value;
|
public static ProfileExHandler Instance => _instance.Value;
|
||||||
private static readonly string _tag = "ProfileExHandler";
|
private static readonly string _tag = "ProfileExHandler";
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ namespace ServiceLib.Handler
|
|||||||
List<ProfileExItem> lstInserts = [];
|
List<ProfileExItem> lstInserts = [];
|
||||||
List<ProfileExItem> lstUpdates = [];
|
List<ProfileExItem> lstUpdates = [];
|
||||||
|
|
||||||
for (int i = 0; i < cnt; i++)
|
for (var i = 0; i < cnt; i++)
|
||||||
{
|
{
|
||||||
var id = _queIndexIds.Dequeue();
|
var id = _queIndexIds.Dequeue();
|
||||||
var item = lstExists.FirstOrDefault(t => t.IndexId == id);
|
var item = lstExists.FirstOrDefault(t => t.IndexId == id);
|
||||||
@@ -78,13 +78,18 @@ namespace ServiceLib.Handler
|
|||||||
lstInserts.Add(itemNew);
|
lstInserts.Add(itemNew);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (lstInserts.Count() > 0)
|
if (lstInserts.Count > 0)
|
||||||
|
{
|
||||||
await SQLiteHelper.Instance.InsertAllAsync(lstInserts);
|
await SQLiteHelper.Instance.InsertAllAsync(lstInserts);
|
||||||
|
}
|
||||||
|
|
||||||
if (lstUpdates.Count() > 0)
|
if (lstUpdates.Count > 0)
|
||||||
|
{
|
||||||
await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates);
|
await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -93,17 +98,24 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddProfileEx(string indexId, ref ProfileExItem? profileEx)
|
private ProfileExItem AddProfileEx(string indexId)
|
||||||
{
|
{
|
||||||
profileEx = new()
|
var profileEx = new ProfileExItem()
|
||||||
{
|
{
|
||||||
IndexId = indexId,
|
IndexId = indexId,
|
||||||
Delay = 0,
|
Delay = 0,
|
||||||
Speed = 0,
|
Speed = 0,
|
||||||
Sort = 0
|
Sort = 0,
|
||||||
|
Message = string.Empty
|
||||||
};
|
};
|
||||||
_lstProfileEx.Add(profileEx);
|
_lstProfileEx.Add(profileEx);
|
||||||
IndexIdEnqueue(indexId);
|
IndexIdEnqueue(indexId);
|
||||||
|
return profileEx;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProfileExItem GetProfileExItem(string? indexId)
|
||||||
|
{
|
||||||
|
return _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId) ?? AddProfileEx(indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ClearAll()
|
public async Task ClearAll()
|
||||||
@@ -124,39 +136,34 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTestDelay(string indexId, string delayVal)
|
public void SetTestDelay(string indexId, int delay)
|
||||||
{
|
{
|
||||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
|
var profileEx = GetProfileExItem(indexId);
|
||||||
if (profileEx == null)
|
|
||||||
{
|
|
||||||
AddProfileEx(indexId, ref profileEx);
|
|
||||||
}
|
|
||||||
|
|
||||||
int.TryParse(delayVal, out int delay);
|
|
||||||
profileEx.Delay = delay;
|
profileEx.Delay = delay;
|
||||||
IndexIdEnqueue(indexId);
|
IndexIdEnqueue(indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTestSpeed(string indexId, string speedVal)
|
public void SetTestSpeed(string indexId, decimal speed)
|
||||||
{
|
{
|
||||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
|
var profileEx = GetProfileExItem(indexId);
|
||||||
if (profileEx == null)
|
|
||||||
{
|
|
||||||
AddProfileEx(indexId, ref profileEx);
|
|
||||||
}
|
|
||||||
|
|
||||||
decimal.TryParse(speedVal, out decimal speed);
|
|
||||||
profileEx.Speed = speed;
|
profileEx.Speed = speed;
|
||||||
IndexIdEnqueue(indexId);
|
IndexIdEnqueue(indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetTestMessage(string indexId, string message)
|
||||||
|
{
|
||||||
|
var profileEx = GetProfileExItem(indexId);
|
||||||
|
|
||||||
|
profileEx.Message = message;
|
||||||
|
IndexIdEnqueue(indexId);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetSort(string indexId, int sort)
|
public void SetSort(string indexId, int sort)
|
||||||
{
|
{
|
||||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
|
var profileEx = GetProfileExItem(indexId);
|
||||||
if (profileEx == null)
|
|
||||||
{
|
|
||||||
AddProfileEx(indexId, ref profileEx);
|
|
||||||
}
|
|
||||||
profileEx.Sort = sort;
|
profileEx.Sort = sort;
|
||||||
IndexIdEnqueue(indexId);
|
IndexIdEnqueue(indexId);
|
||||||
}
|
}
|
||||||
@@ -180,4 +187,4 @@ namespace ServiceLib.Handler
|
|||||||
return _lstProfileEx.Max(t => t == null ? 0 : t.Sort);
|
return _lstProfileEx.Max(t => t == null ? 0 : t.Sort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CoreBasicItem
|
public class CoreBasicItem
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
public int SpeedTestTimeout { get; set; }
|
public int SpeedTestTimeout { get; set; }
|
||||||
public string SpeedTestUrl { get; set; }
|
public string SpeedTestUrl { get; set; }
|
||||||
public string SpeedPingTestUrl { get; set; }
|
public string SpeedPingTestUrl { get; set; }
|
||||||
public int SpeedTestPageSize { get; set; }
|
public int MixedConcurrencyCount { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -244,4 +244,4 @@
|
|||||||
public string? Length { get; set; }
|
public string? Length { get; set; }
|
||||||
public string? Interval { get; set; }
|
public string? Interval { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
@@ -11,5 +11,6 @@ namespace ServiceLib.Models
|
|||||||
public int Delay { get; set; }
|
public int Delay { get; set; }
|
||||||
public decimal Speed { get; set; }
|
public decimal Speed { get; set; }
|
||||||
public int Sort { get; set; }
|
public int Sort { get; set; }
|
||||||
|
public string? Message { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ServerTestItem
|
public class ServerTestItem
|
||||||
@@ -8,6 +8,6 @@
|
|||||||
public int Port { get; set; }
|
public int Port { get; set; }
|
||||||
public EConfigType ConfigType { get; set; }
|
public EConfigType ConfigType { get; set; }
|
||||||
public bool AllowTest { get; set; }
|
public bool AllowTest { get; set; }
|
||||||
public int Delay { get; set; }
|
public int QueueNum { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,23 +4,15 @@ namespace ServiceLib.Models
|
|||||||
{
|
{
|
||||||
public class V2rayConfig
|
public class V2rayConfig
|
||||||
{
|
{
|
||||||
public string? remarks { get; set; }
|
|
||||||
|
|
||||||
public Log4Ray log { get; set; }
|
public Log4Ray log { get; set; }
|
||||||
|
|
||||||
public List<Inbounds4Ray> inbounds { get; set; }
|
|
||||||
|
|
||||||
public List<Outbounds4Ray> outbounds { get; set; }
|
|
||||||
|
|
||||||
public Stats4Ray? stats { get; set; }
|
|
||||||
|
|
||||||
public Metrics4Ray? metrics { get; set; }
|
|
||||||
|
|
||||||
public Policy4Ray? policy { get; set; }
|
|
||||||
|
|
||||||
public object dns { get; set; }
|
public object dns { get; set; }
|
||||||
|
public List<Inbounds4Ray> inbounds { get; set; }
|
||||||
|
public List<Outbounds4Ray> outbounds { get; set; }
|
||||||
public Routing4Ray routing { get; set; }
|
public Routing4Ray routing { get; set; }
|
||||||
|
public Metrics4Ray? metrics { get; set; }
|
||||||
|
public Policy4Ray? policy { get; set; }
|
||||||
|
public Stats4Ray? stats { get; set; }
|
||||||
|
public string? remarks { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Stats4Ray
|
public class Stats4Ray
|
||||||
@@ -398,4 +390,4 @@ namespace ServiceLib.Models
|
|||||||
public string? length { get; set; }
|
public string? length { get; set; }
|
||||||
public string? interval { get; set; }
|
public string? interval { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
82
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
82
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -61,7 +61,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Do you want to append rules? Choose yes to append, choose otherwise to replace 的本地化字符串。
|
/// 查找类似 Do you want to append rules? Choose yes to append, choose otherwise to replace. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string AddBatchRoutingRulesYesNo {
|
public static string AddBatchRoutingRulesYesNo {
|
||||||
get {
|
get {
|
||||||
@@ -196,7 +196,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Failed to run Core, please see the log 的本地化字符串。
|
/// 查找类似 Failed to run Core, please check the prompt information 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string FailedToRunCore {
|
public static string FailedToRunCore {
|
||||||
get {
|
get {
|
||||||
@@ -1311,6 +1311,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Remove invalid by test results 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRemoveInvalidServerResult {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRemoveInvalidServerResult", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Remove selected servers (Delete) 的本地化字符串。
|
/// 查找类似 Remove selected servers (Delete) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1680,6 +1689,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 By test result 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuTestServerResult {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuTestServerResult", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 {0} Website 的本地化字符串。
|
/// 查找类似 {0} Website 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1689,15 +1707,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Clear original subscription content 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string MsgClearSubscription {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("MsgClearSubscription", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Download GeoFile: {0} successfully 的本地化字符串。
|
/// 查找类似 Download GeoFile: {0} successfully 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2004,6 +2013,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Removed {0} invalid test results. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string RemoveInvalidServerResultTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("RemoveInvalidServerResultTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Are you sure to remove the rules? 的本地化字符串。
|
/// 查找类似 Are you sure to remove the rules? 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2204,7 +2222,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 AutoRefresh 的本地化字符串。
|
/// 查找类似 Auto refresh 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbAutoRefresh {
|
public static string TbAutoRefresh {
|
||||||
get {
|
get {
|
||||||
@@ -2213,7 +2231,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Auto ScrollToEnd 的本地化字符串。
|
/// 查找类似 Auto scroll to end 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbAutoScrollToEnd {
|
public static string TbAutoScrollToEnd {
|
||||||
get {
|
get {
|
||||||
@@ -3112,15 +3130,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 HTTP Port 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsHttpPort {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsHttpPort", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Hysteria Max bandwidth (Up/Dw) 的本地化字符串。
|
/// 查找类似 Hysteria Max bandwidth (Up/Dw) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3176,7 +3185,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 The password is encrypted and stored only in local files. 的本地化字符串。
|
/// 查找类似 The password is encrypted and stored only in local files 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsLinuxSudoPasswordTip {
|
public static string TbSettingsLinuxSudoPasswordTip {
|
||||||
get {
|
get {
|
||||||
@@ -3220,6 +3229,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 The number of concurrent during multi-test 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsMixedConcurrencyCount {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsMixedConcurrencyCount", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 sing-box Mux Protocol 的本地化字符串。
|
/// 查找类似 sing-box Mux Protocol 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3355,15 +3373,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Number per time for auto batch during speedtest(max 1000) 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsSpeedTestPageSize {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsSpeedTestPageSize", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 SpeedTest Single Timeout Value 的本地化字符串。
|
/// 查找类似 SpeedTest Single Timeout Value 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3877,15 +3886,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 You are currently running a standalone package, please manually download the SelfContained.7z file to unzip and overwrite it! 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string UpdateStandalonePackageTip {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("UpdateStandalonePackageTip", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 UpgradeApp does not exist 的本地化字符串。
|
/// 查找类似 UpgradeApp does not exist 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@@ -210,9 +210,6 @@
|
|||||||
<data name="LvTransportProtocol" xml:space="preserve">
|
<data name="LvTransportProtocol" xml:space="preserve">
|
||||||
<value>جابجایی</value>
|
<value>جابجایی</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgClearSubscription" xml:space="preserve">
|
|
||||||
<value>محتوای اشتراک اصلی را پاک کنید</value>
|
|
||||||
</data>
|
|
||||||
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
||||||
<value>دانلود Core با موفقیت</value>
|
<value>دانلود Core با موفقیت</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -344,10 +341,10 @@
|
|||||||
<value>لطفاً DNS سفارشی صحیح را پر کنید</value>
|
<value>لطفاً DNS سفارشی صحیح را پر کنید</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip1" xml:space="preserve">
|
<data name="TransportPathTip1" xml:space="preserve">
|
||||||
<value>*ws path</value>
|
<value>* مسیر ws</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportPathTip2" xml:space="preserve">
|
<data name="TransportPathTip2" xml:space="preserve">
|
||||||
<value>*h2 path</value>
|
<value>* مسیر h2</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>
|
||||||
@@ -356,13 +353,13 @@
|
|||||||
<value>*grpc serviceName</value>
|
<value>*grpc serviceName</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip1" xml:space="preserve">
|
<data name="TransportRequestHostTip1" xml:space="preserve">
|
||||||
<value>*http host Separated by commas (,)</value>
|
<value>*هاست http جدا شده با کاما (،)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip2" xml:space="preserve">
|
<data name="TransportRequestHostTip2" xml:space="preserve">
|
||||||
<value>*ws host</value>
|
<value>*هاست ws</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip3" xml:space="preserve">
|
<data name="TransportRequestHostTip3" xml:space="preserve">
|
||||||
<value>*h2 host Separated by commas (,)</value>
|
<value>*هاست h2 با کاما (،) جدا شده است</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportRequestHostTip4" xml:space="preserve">
|
<data name="TransportRequestHostTip4" xml:space="preserve">
|
||||||
<value>*QUIC securty</value>
|
<value>*QUIC securty</value>
|
||||||
@@ -377,7 +374,7 @@
|
|||||||
<value>*QUIC camouflage type</value>
|
<value>*QUIC camouflage type</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TransportHeaderTypeTip4" xml:space="preserve">
|
<data name="TransportHeaderTypeTip4" xml:space="preserve">
|
||||||
<value>*grpc mode</value>
|
<value>*حالت grpc</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvTLS" xml:space="preserve">
|
<data name="LvTLS" xml:space="preserve">
|
||||||
<value>TLS</value>
|
<value>TLS</value>
|
||||||
@@ -404,7 +401,7 @@
|
|||||||
<value>درحال تست کردن...</value>
|
<value>درحال تست کردن...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LabLAN" xml:space="preserve">
|
<data name="LabLAN" xml:space="preserve">
|
||||||
<value>LAN</value>
|
<value>شبکه محلی</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LabLocal" xml:space="preserve">
|
<data name="LabLocal" xml:space="preserve">
|
||||||
<value>محلی</value>
|
<value>محلی</value>
|
||||||
@@ -715,9 +712,6 @@
|
|||||||
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
||||||
<value>استثناها: از سرور پروکسی برای آدرس هایی که با موارد زیر شروع می شوند استفاده نکنید. برای جدا کردن ورودی ها از نقطه ویرگول (;) استفاده کنید.</value>
|
<value>استثناها: از سرور پروکسی برای آدرس هایی که با موارد زیر شروع می شوند استفاده نکنید. برای جدا کردن ورودی ها از نقطه ویرگول (;) استفاده کنید.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
|
||||||
<value>پورت Http</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||||
<value>نمایش سرعت واقعی (نیاز به راه اندازی مجدد)</value>
|
<value>نمایش سرعت واقعی (نیاز به راه اندازی مجدد)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1051,9 +1045,6 @@
|
|||||||
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
||||||
<value>نمایش یا پنهان کردن پنجره اصلی</value>
|
<value>نمایش یا پنهان کردن پنجره اصلی</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UpdateStandalonePackageTip" xml:space="preserve">
|
|
||||||
<value>شما در حال حاضر در حال اجرای یک بسته مستقل هستید، لطفاً فایل SelfContained.7z را به صورت دستی دانلود کنید تا آن را از حالت فشرده خارج کرده و بازنویسی کنید!</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
<value>پیکربندی سفارشی ساکس پورت</value>
|
<value>پیکربندی سفارشی ساکس پورت</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1372,8 +1363,8 @@
|
|||||||
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
||||||
<value>هنگام بستن پنجره در سینی پنهان شوید</value>
|
<value>هنگام بستن پنجره در سینی پنهان شوید</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
|
<data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
|
||||||
<value>تعداد در هر زمان برای دسته خودکار در طول تست سرعت (حداکثر 1000)</value>
|
<value>The number of concurrent during multi-test</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||||
<value>موارد استثنا: از سرور پروکسی برای آدرس های زیر استفاده نکنید. برای جدا کردن ورودی ها از کاما (،) استفاده کنید.</value>
|
<value>موارد استثنا: از سرور پروکسی برای آدرس های زیر استفاده نکنید. برای جدا کردن ورودی ها از کاما (،) استفاده کنید.</value>
|
||||||
@@ -1394,6 +1385,15 @@
|
|||||||
<value>کپی کردن دستور پروکسی در کلیپ بورد</value>
|
<value>کپی کردن دستور پروکسی در کلیپ بورد</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
||||||
<value>Starting retesting failed parts, {0} remaining. Press ESC to terminate...</value>
|
<value>شروع آزمایش مجدد قطعات ناموفق، {0} باقی مانده است. برای خاتمه ESC را فشار دهید...</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuTestServerResult" xml:space="preserve">
|
||||||
|
<value>By test result</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoveInvalidServerResult" xml:space="preserve">
|
||||||
|
<value>Remove invalid by test results</value>
|
||||||
|
</data>
|
||||||
|
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||||
|
<value>Removed {0} invalid test results.</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@@ -210,9 +210,6 @@
|
|||||||
<data name="LvTransportProtocol" xml:space="preserve">
|
<data name="LvTransportProtocol" xml:space="preserve">
|
||||||
<value>Szállítás</value>
|
<value>Szállítás</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgClearSubscription" xml:space="preserve">
|
|
||||||
<value>Eredeti előfizetési tartalom törlése</value>
|
|
||||||
</data>
|
|
||||||
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
||||||
<value>A Core letöltése sikerült</value>
|
<value>A Core letöltése sikerült</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -715,9 +712,6 @@
|
|||||||
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
||||||
<value>Kivétel. Ne használjon proxy szervert a címek esetében, amelyek pontosan itt kezdődnek, használjon pontosvesszőt (;)</value>
|
<value>Kivétel. Ne használjon proxy szervert a címek esetében, amelyek pontosan itt kezdődnek, használjon pontosvesszőt (;)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
|
||||||
<value>HTTP Port</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||||
<value>Display real-time speed</value>
|
<value>Display real-time speed</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1255,9 +1249,6 @@
|
|||||||
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
||||||
<value>Fő ablak megjelenítése vagy elrejtése</value>
|
<value>Fő ablak megjelenítése vagy elrejtése</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UpdateStandalonePackageTip" xml:space="preserve">
|
|
||||||
<value>Jelenleg egy önálló csomagot futtatsz, kérlek, töltsd le manuálisan a SelfContained.7z fájlt, bontsd ki és írd felül!</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
<value>Testreszabott konfigurációs socks port</value>
|
<value>Testreszabott konfigurációs socks port</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1372,8 +1363,8 @@
|
|||||||
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
||||||
<value>Minimálás tálcára ablak zárásakor</value>
|
<value>Minimálás tálcára ablak zárásakor</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
|
<data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
|
||||||
<value>Szám / időszak az automatikus batch során a sebességvizsgálat során (maximum 1000)</value>
|
<value>The number of concurrent during multi-test</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||||
<value>Kivétel. Ne használj proxy szervert a címeknél, évezz pontosvesszőt (,)</value>
|
<value>Kivétel. Ne használj proxy szervert a címeknél, évezz pontosvesszőt (,)</value>
|
||||||
@@ -1396,4 +1387,13 @@
|
|||||||
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
||||||
<value>Starting retesting failed parts, {0} remaining. Press ESC to terminate...</value>
|
<value>Starting retesting failed parts, {0} remaining. Press ESC to terminate...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuTestServerResult" xml:space="preserve">
|
||||||
|
<value>By test result</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoveInvalidServerResult" xml:space="preserve">
|
||||||
|
<value>Remove invalid by test results</value>
|
||||||
|
</data>
|
||||||
|
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||||
|
<value>Removed {0} invalid test results.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@@ -210,9 +210,6 @@
|
|||||||
<data name="LvTransportProtocol" xml:space="preserve">
|
<data name="LvTransportProtocol" xml:space="preserve">
|
||||||
<value>Transport</value>
|
<value>Transport</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgClearSubscription" xml:space="preserve">
|
|
||||||
<value>Clear original subscription content</value>
|
|
||||||
</data>
|
|
||||||
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
||||||
<value>Download Core successfully</value>
|
<value>Download Core successfully</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -329,7 +326,7 @@
|
|||||||
<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>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve">
|
<data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve">
|
||||||
<value>Download GeoFile: {0} successfully</value>
|
<value>Download GeoFile: {0} successfully</value>
|
||||||
@@ -715,9 +712,6 @@
|
|||||||
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
||||||
<value>Exclusions: Do not use proxy server for addresses beginning with the following. Use semicolon (;) to separate entries.</value>
|
<value>Exclusions: Do not use proxy server for addresses beginning with the following. Use semicolon (;) to separate entries.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
|
||||||
<value>HTTP Port</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||||
<value>Display real-time speed (requires restart)</value>
|
<value>Display real-time speed (requires restart)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -926,7 +920,7 @@
|
|||||||
<value>Speed(M/s)</value>
|
<value>Speed(M/s)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedToRunCore" xml:space="preserve">
|
<data name="FailedToRunCore" xml:space="preserve">
|
||||||
<value>Failed to run Core, please see the log</value>
|
<value>Failed to run Core, please check the prompt information</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvFilter" xml:space="preserve">
|
<data name="LvFilter" xml:space="preserve">
|
||||||
<value>Remarks regular filter</value>
|
<value>Remarks regular filter</value>
|
||||||
@@ -950,7 +944,7 @@
|
|||||||
<value>Enable sorting servers by drag-n-drop (requires restart)</value>
|
<value>Enable sorting servers by drag-n-drop (requires restart)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoRefresh" xml:space="preserve">
|
<data name="TbAutoRefresh" xml:space="preserve">
|
||||||
<value>AutoRefresh</value>
|
<value>Auto refresh</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingSkip" xml:space="preserve">
|
<data name="SpeedtestingSkip" xml:space="preserve">
|
||||||
<value>Skip test</value>
|
<value>Skip test</value>
|
||||||
@@ -1115,7 +1109,7 @@
|
|||||||
<value>(Domain or IP or ProcName) and Port and Protocol and InboundTag => OutboundTag</value>
|
<value>(Domain or IP or ProcName) and Port and Protocol and InboundTag => OutboundTag</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoScrollToEnd" xml:space="preserve">
|
<data name="TbAutoScrollToEnd" xml:space="preserve">
|
||||||
<value>Auto ScrollToEnd</value>
|
<value>Auto scroll to end</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
|
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
|
||||||
<value>Speed Ping Test URL</value>
|
<value>Speed Ping Test URL</value>
|
||||||
@@ -1255,9 +1249,6 @@
|
|||||||
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
||||||
<value>Show or hide the main window</value>
|
<value>Show or hide the main window</value>
|
||||||
</data>
|
</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">
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
<value>Custom config socks port</value>
|
<value>Custom config socks port</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1355,7 +1346,7 @@
|
|||||||
<value>System sudo password</value>
|
<value>System sudo password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>The password is encrypted and stored only in local files.</value>
|
<value>The password is encrypted and stored only in local files</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||||
<value>Please set the sudo password in Tun mode settings first</value>
|
<value>Please set the sudo password in Tun mode settings first</value>
|
||||||
@@ -1372,8 +1363,8 @@
|
|||||||
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
||||||
<value>Hide to tray when closing the window</value>
|
<value>Hide to tray when closing the window</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
|
<data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
|
||||||
<value>Number per time for auto batch during speedtest(max 1000)</value>
|
<value>The number of concurrent during multi-test</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||||
<value>Exclusions: Do not use proxy server for the following addresses. Use comma (,) to separate entries.</value>
|
<value>Exclusions: Do not use proxy server for the following addresses. Use comma (,) to separate entries.</value>
|
||||||
@@ -1396,4 +1387,13 @@
|
|||||||
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
||||||
<value>Starting retesting failed parts, {0} remaining. Press ESC to terminate...</value>
|
<value>Starting retesting failed parts, {0} remaining. Press ESC to terminate...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuTestServerResult" xml:space="preserve">
|
||||||
|
<value>By test result</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoveInvalidServerResult" xml:space="preserve">
|
||||||
|
<value>Remove invalid by test results</value>
|
||||||
|
</data>
|
||||||
|
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||||
|
<value>Removed {0} invalid test results.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@@ -210,9 +210,6 @@
|
|||||||
<data name="LvTransportProtocol" xml:space="preserve">
|
<data name="LvTransportProtocol" xml:space="preserve">
|
||||||
<value>Протокол</value>
|
<value>Протокол</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgClearSubscription" xml:space="preserve">
|
|
||||||
<value>Очистить контент оригинальной подписки</value>
|
|
||||||
</data>
|
|
||||||
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
||||||
<value>Ядро успешно загружено</value>
|
<value>Ядро успешно загружено</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -721,9 +718,6 @@
|
|||||||
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
||||||
<value>Исключение. Не используйте прокси-сервер для адресов, начинающихся с (,), используйте точку с запятой (;)</value>
|
<value>Исключение. Не используйте прокси-сервер для адресов, начинающихся с (,), используйте точку с запятой (;)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
|
||||||
<value>HTTP порт</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||||
<value>Display real-time speed</value>
|
<value>Display real-time speed</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1210,9 +1204,6 @@
|
|||||||
<data name="menuAddTuicServer" xml:space="preserve">
|
<data name="menuAddTuicServer" xml:space="preserve">
|
||||||
<value>Add [TUIC] server</value>
|
<value>Add [TUIC] server</value>
|
||||||
</data>
|
</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="TbSettingsEnableIPv6Address" xml:space="preserve">
|
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
||||||
<value>Enable IPv6 Address</value>
|
<value>Enable IPv6 Address</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1372,8 +1363,8 @@
|
|||||||
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
||||||
<value>Hide to tray when closing the window</value>
|
<value>Hide to tray when closing the window</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
|
<data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
|
||||||
<value>Number per time for auto batch during speedtest(max 1000)</value>
|
<value>The number of concurrent during multi-test</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||||
<value>Exception. Do not use proxy server for addresses,with a comma (,)</value>
|
<value>Exception. Do not use proxy server for addresses,with a comma (,)</value>
|
||||||
@@ -1396,4 +1387,13 @@
|
|||||||
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
||||||
<value>Starting retesting failed parts, {0} remaining. Press ESC to terminate...</value>
|
<value>Starting retesting failed parts, {0} remaining. Press ESC to terminate...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuTestServerResult" xml:space="preserve">
|
||||||
|
<value>By test result</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoveInvalidServerResult" xml:space="preserve">
|
||||||
|
<value>Remove invalid by test results</value>
|
||||||
|
</data>
|
||||||
|
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||||
|
<value>Removed {0} invalid test results.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@@ -175,10 +175,10 @@
|
|||||||
<value>初始化配置</value>
|
<value>初始化配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestCore" xml:space="preserve">
|
<data name="IsLatestCore" xml:space="preserve">
|
||||||
<value>{0} {1} 已是最新版本</value>
|
<value>{0} {1} 已是最新版本。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestN" xml:space="preserve">
|
<data name="IsLatestN" xml:space="preserve">
|
||||||
<value>{0} {1} 已是最新版本</value>
|
<value>{0} {1} 已是最新版本。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvAddress" xml:space="preserve">
|
<data name="LvAddress" xml:space="preserve">
|
||||||
<value>地址</value>
|
<value>地址</value>
|
||||||
@@ -210,9 +210,6 @@
|
|||||||
<data name="LvTransportProtocol" xml:space="preserve">
|
<data name="LvTransportProtocol" xml:space="preserve">
|
||||||
<value>传输协议</value>
|
<value>传输协议</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgClearSubscription" xml:space="preserve">
|
|
||||||
<value>清除原订阅内容</value>
|
|
||||||
</data>
|
|
||||||
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
||||||
<value>下载Core成功</value>
|
<value>下载Core成功</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -277,7 +274,7 @@
|
|||||||
<value>请先选择服务器</value>
|
<value>请先选择服务器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
||||||
<value>服务器去重完成。原数量: {0},现数量: {1}</value>
|
<value>服务器去重完成。原数量: {0},现数量: {1}。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveServer" xml:space="preserve">
|
<data name="RemoveServer" xml:space="preserve">
|
||||||
<value>是否确定移除服务器?</value>
|
<value>是否确定移除服务器?</value>
|
||||||
@@ -715,9 +712,6 @@
|
|||||||
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
||||||
<value>例外:对于下列字符开头的地址,不使用代理配置文件。使用分号(;)分隔。</value>
|
<value>例外:对于下列字符开头的地址,不使用代理配置文件。使用分号(;)分隔。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
|
||||||
<value>本地http监听端口</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||||
<value>显示实时速度(需重启)</value>
|
<value>显示实时速度(需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -926,7 +920,7 @@
|
|||||||
<value>速度(M/s)</value>
|
<value>速度(M/s)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedToRunCore" xml:space="preserve">
|
<data name="FailedToRunCore" xml:space="preserve">
|
||||||
<value>运行Core失败,请查看日志</value>
|
<value>运行 Core 失败,请查看提示信息</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvFilter" xml:space="preserve">
|
<data name="LvFilter" xml:space="preserve">
|
||||||
<value>别名正则过滤</value>
|
<value>别名正则过滤</value>
|
||||||
@@ -1252,9 +1246,6 @@
|
|||||||
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
||||||
<value>显示或隐藏主界面</value>
|
<value>显示或隐藏主界面</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UpdateStandalonePackageTip" xml:space="preserve">
|
|
||||||
<value>您当前运行的是独立包,请手动下载 SelfContained.7z文件解压覆盖!</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
<value>自定义配置的Socks端口</value>
|
<value>自定义配置的Socks端口</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1369,8 +1360,8 @@
|
|||||||
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
||||||
<value>关闭窗口时隐藏至托盘</value>
|
<value>关闭窗口时隐藏至托盘</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
|
<data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
|
||||||
<value>测试时自动分批的每批数量(最大1000)</value>
|
<value>多线程测试时的并发数量</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||||
<value>例外:对于下列地址不使用代理配置文件。使用逗号(,)分隔。</value>
|
<value>例外:对于下列地址不使用代理配置文件。使用逗号(,)分隔。</value>
|
||||||
@@ -1393,4 +1384,13 @@
|
|||||||
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
||||||
<value>开始对失败部分进行重新测试,剩余 {0} 个。可按 ESC 终止...</value>
|
<value>开始对失败部分进行重新测试,剩余 {0} 个。可按 ESC 终止...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuTestServerResult" xml:space="preserve">
|
||||||
|
<value>按测试结果</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoveInvalidServerResult" xml:space="preserve">
|
||||||
|
<value>按测试结果移除无效</value>
|
||||||
|
</data>
|
||||||
|
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||||
|
<value>移除无效测试结果 {0} 个。</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -175,10 +175,10 @@
|
|||||||
<value>初始化設定</value>
|
<value>初始化設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestCore" xml:space="preserve">
|
<data name="IsLatestCore" xml:space="preserve">
|
||||||
<value>{0} {1} 已是最新版本</value>
|
<value>{0} {1} 已是最新版本。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IsLatestN" xml:space="preserve">
|
<data name="IsLatestN" xml:space="preserve">
|
||||||
<value>{0} {1} 已是最新版本</value>
|
<value>{0} {1} 已是最新版本。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvAddress" xml:space="preserve">
|
<data name="LvAddress" xml:space="preserve">
|
||||||
<value>位址</value>
|
<value>位址</value>
|
||||||
@@ -210,9 +210,6 @@
|
|||||||
<data name="LvTransportProtocol" xml:space="preserve">
|
<data name="LvTransportProtocol" xml:space="preserve">
|
||||||
<value>傳輸協定</value>
|
<value>傳輸協定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgClearSubscription" xml:space="preserve">
|
|
||||||
<value>清除原訂閱內容</value>
|
|
||||||
</data>
|
|
||||||
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
|
||||||
<value>下載Core成功</value>
|
<value>下載Core成功</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -277,7 +274,7 @@
|
|||||||
<value>請先選擇伺服器</value>
|
<value>請先選擇伺服器</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
||||||
<value>伺服器去重完成。原數量: {0},現數量: {1}</value>
|
<value>伺服器去重完成。原數量: {0},現數量: {1}。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveServer" xml:space="preserve">
|
<data name="RemoveServer" xml:space="preserve">
|
||||||
<value>是否確定移除伺服器?</value>
|
<value>是否確定移除伺服器?</value>
|
||||||
@@ -716,9 +713,6 @@
|
|||||||
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
<data name="TbSettingsExceptionTip" xml:space="preserve">
|
||||||
<value>例外:對於下列字元開頭的位址,不使用代理設定檔。使用分號(;)分隔。</value>
|
<value>例外:對於下列字元開頭的位址,不使用代理設定檔。使用分號(;)分隔。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHttpPort" xml:space="preserve">
|
|
||||||
<value>本機HTTP偵聽埠</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
|
||||||
<value>顯示即時速度(需重啟)</value>
|
<value>顯示即時速度(需重啟)</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -927,7 +921,7 @@
|
|||||||
<value>速度(M/s)</value>
|
<value>速度(M/s)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedToRunCore" xml:space="preserve">
|
<data name="FailedToRunCore" xml:space="preserve">
|
||||||
<value>執行Core失敗,請查閲日誌</value>
|
<value>執行Core失敗,請查看提示訊息</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvFilter" xml:space="preserve">
|
<data name="LvFilter" xml:space="preserve">
|
||||||
<value>別名正則過濾</value>
|
<value>別名正則過濾</value>
|
||||||
@@ -1133,9 +1127,6 @@
|
|||||||
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
||||||
<value>顯示或隱藏主介面</value>
|
<value>顯示或隱藏主介面</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UpdateStandalonePackageTip" xml:space="preserve">
|
|
||||||
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋!</value>
|
|
||||||
</data>
|
|
||||||
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
<data name="TbPreSocksPort4Sub" xml:space="preserve">
|
||||||
<value>自訂設定的Socks連接埠</value>
|
<value>自訂設定的Socks連接埠</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -1370,8 +1361,8 @@
|
|||||||
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
|
||||||
<value>關閉視窗時隱藏至托盤</value>
|
<value>關閉視窗時隱藏至托盤</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
|
<data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
|
||||||
<value>測試時自動分批的每批數量(最大1000)</value>
|
<value>多執行緒測試時的並發數量</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
<data name="TbSettingsExceptionTip2" xml:space="preserve">
|
||||||
<value>例外:對於下列位址不使用代理設定檔,使用逗號(,)分隔。</value>
|
<value>例外:對於下列位址不使用代理設定檔,使用逗號(,)分隔。</value>
|
||||||
@@ -1394,4 +1385,13 @@
|
|||||||
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
|
||||||
<value>開始對失敗部分進行重新測試,剩餘 {0} 個。可按 ESC 終止...</value>
|
<value>開始對失敗部分進行重新測試,剩餘 {0} 個。可按 ESC 終止...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuTestServerResult" xml:space="preserve">
|
||||||
|
<value>按測試結果</value>
|
||||||
|
</data>
|
||||||
|
<data name="menuRemoveInvalidServerResult" xml:space="preserve">
|
||||||
|
<value>按測試結果移除無效</value>
|
||||||
|
</data>
|
||||||
|
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||||
|
<value>移除無效測試結果 {0} 個。</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -128,7 +128,7 @@ namespace ServiceLib.Services.CoreConfig
|
|||||||
//Mixin
|
//Mixin
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MixinContent(fileContent, node);
|
await MixinContent(fileContent, node);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -158,20 +158,21 @@ namespace ServiceLib.Services.CoreConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MixinContent(Dictionary<string, object> fileContent, ProfileItem node)
|
private async Task MixinContent(Dictionary<string, object> fileContent, ProfileItem node)
|
||||||
{
|
{
|
||||||
//if (!_config.clashUIItem.enableMixinContent)
|
if (!_config.ClashUIItem.EnableMixinContent)
|
||||||
//{
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
var path = Utils.GetConfigPath(Global.ClashMixinConfigFileName);
|
|
||||||
if (!File.Exists(path))
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var txtFile = File.ReadAllText(Utils.GetConfigPath(Global.ClashMixinConfigFileName));
|
var path = Utils.GetConfigPath(Global.ClashMixinConfigFileName);
|
||||||
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
|
var mixin = EmbedUtils.GetEmbedText(Global.ClashMixinYaml);
|
||||||
|
await File.AppendAllTextAsync(path, mixin);
|
||||||
|
}
|
||||||
|
|
||||||
|
var txtFile = await File.ReadAllTextAsync(Utils.GetConfigPath(Global.ClashMixinConfigFileName));
|
||||||
|
|
||||||
var mixinContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
|
var mixinContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
|
||||||
if (mixinContent == null)
|
if (mixinContent == null)
|
||||||
@@ -269,4 +270,4 @@ namespace ServiceLib.Services.CoreConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -242,6 +242,66 @@ namespace ServiceLib.Services.CoreConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<RetResult> GenerateClientSpeedtestConfig(ProfileItem node, int port)
|
||||||
|
{
|
||||||
|
var ret = new RetResult();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (node is not { Port: > 0 })
|
||||||
|
{
|
||||||
|
ret.Msg = ResUI.CheckServerSettings;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.xhttp))
|
||||||
|
{
|
||||||
|
ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.Msg = ResUI.InitialConfiguration;
|
||||||
|
|
||||||
|
var result = EmbedUtils.GetEmbedText(Global.SingboxSampleClient);
|
||||||
|
if (Utils.IsNullOrEmpty(result))
|
||||||
|
{
|
||||||
|
ret.Msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
var singboxConfig = JsonUtils.Deserialize<SingboxConfig>(result);
|
||||||
|
if (singboxConfig == null)
|
||||||
|
{
|
||||||
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
await GenLog(singboxConfig);
|
||||||
|
await GenOutbound(node, singboxConfig.outbounds.First());
|
||||||
|
await GenMoreOutbounds(node, singboxConfig);
|
||||||
|
await GenDnsDomains(null, singboxConfig, null);
|
||||||
|
|
||||||
|
singboxConfig.route.rules.Clear();
|
||||||
|
singboxConfig.inbounds.Clear();
|
||||||
|
singboxConfig.inbounds.Add(new()
|
||||||
|
{
|
||||||
|
tag = $"{EInboundProtocol.mixed}{port}",
|
||||||
|
listen = Global.Loopback,
|
||||||
|
listen_port = port,
|
||||||
|
type = EInboundProtocol.mixed.ToString(),
|
||||||
|
});
|
||||||
|
|
||||||
|
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||||
|
ret.Success = true;
|
||||||
|
ret.Data = JsonUtils.Serialize(singboxConfig);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<RetResult> GenerateClientMultipleLoadConfig(List<ProfileItem> selecteds)
|
public async Task<RetResult> GenerateClientMultipleLoadConfig(List<ProfileItem> selecteds)
|
||||||
{
|
{
|
||||||
var ret = new RetResult();
|
var ret = new RetResult();
|
||||||
@@ -1264,7 +1324,7 @@ namespace ServiceLib.Services.CoreConfig
|
|||||||
singboxConfig.experimental.cache_file = new CacheFile4Sbox()
|
singboxConfig.experimental.cache_file = new CacheFile4Sbox()
|
||||||
{
|
{
|
||||||
enabled = true,
|
enabled = true,
|
||||||
path = Utils.GetConfigPath("cache.db")
|
path = Utils.GetBinPath("cache.db")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -353,6 +353,64 @@ namespace ServiceLib.Services.CoreConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<RetResult> GenerateClientSpeedtestConfig(ProfileItem node, int port)
|
||||||
|
{
|
||||||
|
var ret = new RetResult();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (node is not { Port: > 0 })
|
||||||
|
{
|
||||||
|
ret.Msg = ResUI.CheckServerSettings;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.GetNetwork() is nameof(ETransport.quic))
|
||||||
|
{
|
||||||
|
ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
|
||||||
|
if (Utils.IsNullOrEmpty(result))
|
||||||
|
{
|
||||||
|
ret.Msg = ResUI.FailedGetDefaultConfiguration;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
var v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(result);
|
||||||
|
if (v2rayConfig == null)
|
||||||
|
{
|
||||||
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
await GenLog(v2rayConfig);
|
||||||
|
await GenOutbound(node, v2rayConfig.outbounds.First());
|
||||||
|
await GenMoreOutbounds(node, v2rayConfig);
|
||||||
|
|
||||||
|
v2rayConfig.routing.rules.Clear();
|
||||||
|
v2rayConfig.inbounds.Clear();
|
||||||
|
v2rayConfig.inbounds.Add(new()
|
||||||
|
{
|
||||||
|
tag = $"{EInboundProtocol.socks}{port}",
|
||||||
|
listen = Global.Loopback,
|
||||||
|
port = port,
|
||||||
|
protocol = EInboundProtocol.socks.ToString(),
|
||||||
|
});
|
||||||
|
|
||||||
|
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||||
|
ret.Success = true;
|
||||||
|
ret.Data = JsonUtils.Serialize(v2rayConfig);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion public gen function
|
#endregion public gen function
|
||||||
|
|
||||||
#region private gen function
|
#region private gen function
|
||||||
|
|||||||
@@ -1,76 +1,69 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using ReactiveUI;
|
|
||||||
|
|
||||||
namespace ServiceLib.Services
|
namespace ServiceLib.Services
|
||||||
{
|
{
|
||||||
public class SpeedtestService
|
public class SpeedtestService
|
||||||
{
|
{
|
||||||
|
private static readonly string _tag = "SpeedtestService";
|
||||||
private Config? _config;
|
private Config? _config;
|
||||||
private Action<SpeedTestResult>? _updateFunc;
|
private Action<SpeedTestResult>? _updateFunc;
|
||||||
|
private static readonly ConcurrentBag<string> _lstExitLoop = new();
|
||||||
|
|
||||||
private bool _exitLoop = false;
|
public SpeedtestService(Config config, Action<SpeedTestResult> updateFunc)
|
||||||
private static readonly string _tag = "SpeedtestService";
|
|
||||||
|
|
||||||
public SpeedtestService(Config config, ESpeedActionType actionType, List<ProfileItem> selecteds, Action<SpeedTestResult> updateFunc)
|
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_updateFunc = updateFunc;
|
_updateFunc = updateFunc;
|
||||||
|
}
|
||||||
|
|
||||||
MessageBus.Current.Listen<string>(EMsgCommand.StopSpeedtest.ToString()).Subscribe(ExitLoop);
|
public void RunLoop(ESpeedActionType actionType, List<ProfileItem> selecteds)
|
||||||
|
{
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var lstSelected = GetClearItem(actionType, selecteds);
|
await RunAsync(actionType, selecteds);
|
||||||
await RunAsync(actionType, lstSelected);
|
await ProfileExHandler.Instance.SaveTo();
|
||||||
UpdateFunc("", ResUI.SpeedtestingCompleted);
|
UpdateFunc("", ResUI.SpeedtestingCompleted);
|
||||||
|
|
||||||
|
FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunAsync(ESpeedActionType actionType, List<ServerTestItem> lstSelected, int pageSize = 0)
|
public void ExitLoop()
|
||||||
{
|
{
|
||||||
if (actionType == ESpeedActionType.Tcping)
|
if (_lstExitLoop.Count > 0)
|
||||||
{
|
{
|
||||||
await RunTcpingAsync(lstSelected);
|
UpdateFunc("", ResUI.SpeedtestingStop);
|
||||||
return;
|
|
||||||
|
_lstExitLoop.Clear();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (pageSize <= 0)
|
private async Task RunAsync(ESpeedActionType actionType, List<ProfileItem> selecteds)
|
||||||
|
{
|
||||||
|
var exitLoopKey = Utils.GetGuid(false);
|
||||||
|
_lstExitLoop.Add(exitLoopKey);
|
||||||
|
|
||||||
|
var lstSelected = GetClearItem(actionType, selecteds);
|
||||||
|
|
||||||
|
switch (actionType)
|
||||||
{
|
{
|
||||||
pageSize = lstSelected.Count < Global.SpeedTestPageSize ? lstSelected.Count : Global.SpeedTestPageSize;
|
case ESpeedActionType.Tcping:
|
||||||
}
|
await RunTcpingAsync(lstSelected);
|
||||||
var lstTest = GetTestBatchItem(lstSelected, pageSize);
|
break;
|
||||||
|
|
||||||
List<ServerTestItem> lstFailed = new();
|
case ESpeedActionType.Realping:
|
||||||
foreach (var lst in lstTest)
|
await RunRealPingBatchAsync(lstSelected, exitLoopKey);
|
||||||
{
|
break;
|
||||||
var ret = actionType switch
|
|
||||||
{
|
|
||||||
ESpeedActionType.Realping => await RunRealPingAsync(lst),
|
|
||||||
ESpeedActionType.Speedtest => await RunSpeedTestAsync(lst),
|
|
||||||
ESpeedActionType.Mixedtest => await RunMixedTestAsync(lst),
|
|
||||||
_ => true
|
|
||||||
};
|
|
||||||
if (ret == false)
|
|
||||||
{
|
|
||||||
lstFailed.AddRange(lst);
|
|
||||||
}
|
|
||||||
await Task.Delay(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Retest the failed part
|
case ESpeedActionType.Speedtest:
|
||||||
var pageSizeNext = pageSize / 2;
|
await RunMixedTestAsync(lstSelected, 1, true, exitLoopKey);
|
||||||
if (lstFailed.Count > 0 && pageSizeNext > 0)
|
break;
|
||||||
{
|
|
||||||
if (_exitLoop)
|
|
||||||
{
|
|
||||||
UpdateFunc("", ResUI.SpeedtestingSkip);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateFunc("", string.Format(ResUI.SpeedtestingTestFailedPart, lstFailed.Count));
|
case ESpeedActionType.Mixedtest:
|
||||||
await RunAsync(actionType, lstFailed, pageSizeNext);
|
await RunMixedTestAsync(lstSelected, _config.SpeedTestItem.MixedConcurrencyCount, true, exitLoopKey);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +87,8 @@ namespace ServiceLib.Services
|
|||||||
IndexId = it.IndexId,
|
IndexId = it.IndexId,
|
||||||
Address = it.Address,
|
Address = it.Address,
|
||||||
Port = it.Port,
|
Port = it.Port,
|
||||||
ConfigType = it.ConfigType
|
ConfigType = it.ConfigType,
|
||||||
|
QueueNum = selecteds.IndexOf(it)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,18 +100,18 @@ namespace ServiceLib.Services
|
|||||||
case ESpeedActionType.Tcping:
|
case ESpeedActionType.Tcping:
|
||||||
case ESpeedActionType.Realping:
|
case ESpeedActionType.Realping:
|
||||||
UpdateFunc(it.IndexId, ResUI.Speedtesting, "");
|
UpdateFunc(it.IndexId, ResUI.Speedtesting, "");
|
||||||
ProfileExHandler.Instance.SetTestDelay(it.IndexId, "0");
|
ProfileExHandler.Instance.SetTestDelay(it.IndexId, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESpeedActionType.Speedtest:
|
case ESpeedActionType.Speedtest:
|
||||||
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingWait);
|
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingWait);
|
||||||
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, "0");
|
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESpeedActionType.Mixedtest:
|
case ESpeedActionType.Mixedtest:
|
||||||
UpdateFunc(it.IndexId, ResUI.Speedtesting, ResUI.SpeedtestingWait);
|
UpdateFunc(it.IndexId, ResUI.Speedtesting, ResUI.SpeedtestingWait);
|
||||||
ProfileExHandler.Instance.SetTestDelay(it.IndexId, "0");
|
ProfileExHandler.Instance.SetTestDelay(it.IndexId, 0);
|
||||||
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, "0");
|
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,72 +119,77 @@ namespace ServiceLib.Services
|
|||||||
return lstSelected;
|
return lstSelected;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<List<ServerTestItem>> GetTestBatchItem(List<ServerTestItem> lstSelected, int pageSize)
|
|
||||||
{
|
|
||||||
List<List<ServerTestItem>> lstTest = new();
|
|
||||||
var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard)).ToList();
|
|
||||||
var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard).ToList();
|
|
||||||
|
|
||||||
for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++)
|
|
||||||
{
|
|
||||||
lstTest.Add(lst1.Skip(num * pageSize).Take(pageSize).ToList());
|
|
||||||
}
|
|
||||||
for (var num = 0; num < (int)Math.Ceiling(lst2.Count * 1.0 / pageSize); num++)
|
|
||||||
{
|
|
||||||
lstTest.Add(lst2.Skip(num * pageSize).Take(pageSize).ToList());
|
|
||||||
}
|
|
||||||
|
|
||||||
return lstTest;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExitLoop(string x)
|
|
||||||
{
|
|
||||||
if (_exitLoop)
|
|
||||||
return;
|
|
||||||
_exitLoop = true;
|
|
||||||
UpdateFunc("", ResUI.SpeedtestingStop);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task RunTcpingAsync(List<ServerTestItem> selecteds)
|
private async Task RunTcpingAsync(List<ServerTestItem> selecteds)
|
||||||
{
|
{
|
||||||
try
|
List<Task> tasks = [];
|
||||||
|
foreach (var it in selecteds)
|
||||||
{
|
{
|
||||||
List<Task> tasks = [];
|
if (it.ConfigType == EConfigType.Custom)
|
||||||
foreach (var it in selecteds)
|
|
||||||
{
|
{
|
||||||
if (it.ConfigType == EConfigType.Custom)
|
continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
tasks.Add(Task.Run(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var time = await GetTcpingTime(it.Address, it.Port);
|
|
||||||
var output = FormatOut(time, Global.DelayUnit);
|
|
||||||
|
|
||||||
ProfileExHandler.Instance.SetTestDelay(it.IndexId, output);
|
|
||||||
UpdateFunc(it.IndexId, output);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
Task.WaitAll([.. tasks]);
|
tasks.Add(Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var responseTime = await GetTcpingTime(it.Address, it.Port);
|
||||||
|
|
||||||
|
ProfileExHandler.Instance.SetTestDelay(it.IndexId, responseTime);
|
||||||
|
UpdateFunc(it.IndexId, responseTime.ToString());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
Task.WaitAll([.. tasks]);
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RunRealPingBatchAsync(List<ServerTestItem> lstSelected, string exitLoopKey, int pageSize = 0)
|
||||||
|
{
|
||||||
|
if (pageSize <= 0)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(_tag, ex);
|
pageSize = lstSelected.Count < Global.SpeedTestPageSize ? lstSelected.Count : Global.SpeedTestPageSize;
|
||||||
}
|
}
|
||||||
finally
|
var lstTest = GetTestBatchItem(lstSelected, pageSize);
|
||||||
|
|
||||||
|
List<ServerTestItem> lstFailed = new();
|
||||||
|
foreach (var lst in lstTest)
|
||||||
{
|
{
|
||||||
await ProfileExHandler.Instance.SaveTo();
|
var ret = await RunRealPingAsync(lst, exitLoopKey);
|
||||||
|
if (ret == false)
|
||||||
|
{
|
||||||
|
lstFailed.AddRange(lst);
|
||||||
|
}
|
||||||
|
await Task.Delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Retest the failed part
|
||||||
|
var pageSizeNext = pageSize / 2;
|
||||||
|
if (lstFailed.Count > 0 && pageSizeNext > 0)
|
||||||
|
{
|
||||||
|
if (_lstExitLoop.Any(p => p == exitLoopKey) == false)
|
||||||
|
{
|
||||||
|
UpdateFunc("", ResUI.SpeedtestingSkip);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateFunc("", string.Format(ResUI.SpeedtestingTestFailedPart, lstFailed.Count));
|
||||||
|
|
||||||
|
if (pageSizeNext > _config.SpeedTestItem.MixedConcurrencyCount)
|
||||||
|
{
|
||||||
|
await RunRealPingBatchAsync(lstFailed, exitLoopKey, pageSizeNext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await RunMixedTestAsync(lstSelected, _config.SpeedTestItem.MixedConcurrencyCount, false, exitLoopKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> RunRealPingAsync(List<ServerTestItem> selecteds)
|
private async Task<bool> RunRealPingAsync(List<ServerTestItem> selecteds, string exitLoopKey)
|
||||||
{
|
{
|
||||||
var pid = -1;
|
var pid = -1;
|
||||||
try
|
try
|
||||||
@@ -216,20 +215,7 @@ namespace ServiceLib.Services
|
|||||||
}
|
}
|
||||||
tasks.Add(Task.Run(async () =>
|
tasks.Add(Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
await DoRealPing(downloadHandle, it);
|
||||||
{
|
|
||||||
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
|
|
||||||
var output = await GetRealPingTime(downloadHandle, webProxy);
|
|
||||||
|
|
||||||
ProfileExHandler.Instance.SetTestDelay(it.IndexId, output);
|
|
||||||
UpdateFunc(it.IndexId, output);
|
|
||||||
int.TryParse(output, out var delay);
|
|
||||||
it.Delay = delay;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Task.WaitAll(tasks.ToArray());
|
Task.WaitAll(tasks.ToArray());
|
||||||
@@ -244,160 +230,90 @@ namespace ServiceLib.Services
|
|||||||
{
|
{
|
||||||
await ProcUtils.ProcessKill(pid);
|
await ProcUtils.ProcessKill(pid);
|
||||||
}
|
}
|
||||||
await ProfileExHandler.Instance.SaveTo();
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> RunSpeedTestAsync(List<ServerTestItem> selecteds)
|
private async Task RunMixedTestAsync(List<ServerTestItem> selecteds, int concurrencyCount, bool blSpeedTest, string exitLoopKey)
|
||||||
{
|
{
|
||||||
var pid = -1;
|
using var concurrencySemaphore = new SemaphoreSlim(concurrencyCount);
|
||||||
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
|
var downloadHandle = new DownloadService();
|
||||||
if (pid < 0)
|
List<Task> tasks = new();
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var url = _config.SpeedTestItem.SpeedTestUrl;
|
|
||||||
var timeout = _config.SpeedTestItem.SpeedTestTimeout;
|
|
||||||
|
|
||||||
DownloadService downloadHandle = new();
|
|
||||||
|
|
||||||
foreach (var it in selecteds)
|
foreach (var it in selecteds)
|
||||||
{
|
{
|
||||||
if (_exitLoop)
|
if (_lstExitLoop.Any(p => p == exitLoopKey) == false)
|
||||||
{
|
{
|
||||||
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
|
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!it.AllowTest)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (it.ConfigType == EConfigType.Custom)
|
if (it.ConfigType == EConfigType.Custom)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//if (it.delay < 0)
|
await concurrencySemaphore.WaitAsync();
|
||||||
//{
|
|
||||||
// UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
|
|
||||||
// continue;
|
|
||||||
//}
|
|
||||||
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, "-1");
|
|
||||||
UpdateFunc(it.IndexId, "", ResUI.Speedtesting);
|
|
||||||
|
|
||||||
var item = await AppHandler.Instance.GetProfileItem(it.IndexId);
|
tasks.Add(Task.Run(async () =>
|
||||||
if (item is null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
|
|
||||||
|
|
||||||
await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) =>
|
|
||||||
{
|
{
|
||||||
decimal.TryParse(msg, out var dec);
|
var pid = -1;
|
||||||
if (dec > 0)
|
try
|
||||||
{
|
{
|
||||||
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg);
|
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(it);
|
||||||
|
if (pid > 0)
|
||||||
|
{
|
||||||
|
await Task.Delay(500);
|
||||||
|
await DoRealPing(downloadHandle, it);
|
||||||
|
if (blSpeedTest)
|
||||||
|
{
|
||||||
|
await DoSpeedTest(downloadHandle, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
UpdateFunc(it.IndexId, "", msg);
|
catch (Exception ex)
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid > 0)
|
|
||||||
{
|
|
||||||
await ProcUtils.ProcessKill(pid);
|
|
||||||
}
|
|
||||||
await ProfileExHandler.Instance.SaveTo();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<bool> RunSpeedTestMulti(List<ServerTestItem> selecteds)
|
|
||||||
{
|
|
||||||
var pid = -1;
|
|
||||||
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
|
|
||||||
if (pid < 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var url = _config.SpeedTestItem.SpeedTestUrl;
|
|
||||||
var timeout = _config.SpeedTestItem.SpeedTestTimeout;
|
|
||||||
|
|
||||||
DownloadService downloadHandle = new();
|
|
||||||
|
|
||||||
foreach (var it in selecteds)
|
|
||||||
{
|
|
||||||
if (_exitLoop)
|
|
||||||
{
|
|
||||||
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!it.AllowTest)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (it.ConfigType == EConfigType.Custom)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (it.Delay < 0)
|
|
||||||
{
|
|
||||||
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, "-1");
|
|
||||||
UpdateFunc(it.IndexId, "", ResUI.Speedtesting);
|
|
||||||
|
|
||||||
var item = await AppHandler.Instance.GetProfileItem(it.IndexId);
|
|
||||||
if (item is null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
|
|
||||||
_ = downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) =>
|
|
||||||
{
|
|
||||||
decimal.TryParse(msg, out var dec);
|
|
||||||
if (dec > 0)
|
|
||||||
{
|
{
|
||||||
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
UpdateFunc(it.IndexId, "", msg);
|
finally
|
||||||
});
|
{
|
||||||
await Task.Delay(2000);
|
if (pid > 0)
|
||||||
|
{
|
||||||
|
await ProcUtils.ProcessKill(pid);
|
||||||
|
}
|
||||||
|
concurrencySemaphore.Release();
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
Task.WaitAll(tasks.ToArray());
|
||||||
await Task.Delay((timeout + 2) * 1000);
|
|
||||||
|
|
||||||
if (pid > 0)
|
|
||||||
{
|
|
||||||
await ProcUtils.ProcessKill(pid);
|
|
||||||
}
|
|
||||||
await ProfileExHandler.Instance.SaveTo();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> RunMixedTestAsync(List<ServerTestItem> selecteds)
|
private async Task DoRealPing(DownloadService downloadHandle, ServerTestItem it)
|
||||||
{
|
|
||||||
var ret = await RunRealPingAsync(selecteds);
|
|
||||||
if (ret == false)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(1000);
|
|
||||||
|
|
||||||
var ret2 = await RunSpeedTestMulti(selecteds);
|
|
||||||
if (ret2 == false)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> GetRealPingTime(DownloadService downloadHandle, IWebProxy webProxy)
|
|
||||||
{
|
{
|
||||||
|
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
|
||||||
var responseTime = await downloadHandle.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
|
var responseTime = await downloadHandle.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
|
||||||
return FormatOut(responseTime, Global.DelayUnit);
|
|
||||||
|
ProfileExHandler.Instance.SetTestDelay(it.IndexId, responseTime);
|
||||||
|
UpdateFunc(it.IndexId, responseTime.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoSpeedTest(DownloadService downloadHandle, ServerTestItem it)
|
||||||
|
{
|
||||||
|
UpdateFunc(it.IndexId, "", ResUI.Speedtesting);
|
||||||
|
|
||||||
|
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
|
||||||
|
var url = _config.SpeedTestItem.SpeedTestUrl;
|
||||||
|
var timeout = _config.SpeedTestItem.SpeedTestTimeout;
|
||||||
|
await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) =>
|
||||||
|
{
|
||||||
|
decimal.TryParse(msg, out var dec);
|
||||||
|
if (dec > 0)
|
||||||
|
{
|
||||||
|
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, dec);
|
||||||
|
}
|
||||||
|
UpdateFunc(it.IndexId, "", msg);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GetTcpingTime(string url, int port)
|
private async Task<int> GetTcpingTime(string url, int port)
|
||||||
@@ -419,7 +335,10 @@ namespace ServiceLib.Services
|
|||||||
|
|
||||||
var 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();
|
||||||
@@ -432,14 +351,31 @@ namespace ServiceLib.Services
|
|||||||
return responseTime;
|
return responseTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string FormatOut(object time, string unit)
|
private List<List<ServerTestItem>> GetTestBatchItem(List<ServerTestItem> lstSelected, int pageSize)
|
||||||
{
|
{
|
||||||
return $"{time}";
|
List<List<ServerTestItem>> lstTest = new();
|
||||||
|
var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard)).ToList();
|
||||||
|
var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard).ToList();
|
||||||
|
|
||||||
|
for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++)
|
||||||
|
{
|
||||||
|
lstTest.Add(lst1.Skip(num * pageSize).Take(pageSize).ToList());
|
||||||
|
}
|
||||||
|
for (var num = 0; num < (int)Math.Ceiling(lst2.Count * 1.0 / pageSize); num++)
|
||||||
|
{
|
||||||
|
lstTest.Add(lst2.Skip(num * pageSize).Take(pageSize).ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
return lstTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateFunc(string indexId, string delay, string speed = "")
|
private void UpdateFunc(string indexId, string delay, string speed = "")
|
||||||
{
|
{
|
||||||
_updateFunc?.Invoke(new() { IndexId = indexId, Delay = delay, Speed = speed });
|
_updateFunc?.Invoke(new() { IndexId = indexId, Delay = delay, Speed = speed });
|
||||||
|
if (indexId.IsNotEmpty() && speed.IsNotEmpty())
|
||||||
|
{
|
||||||
|
ProfileExHandler.Instance.SetTestMessage(indexId, speed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace ServiceLib.Services.Statistics
|
|||||||
Task.Run(Run);
|
Task.Run(Run);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Init()
|
private async Task Init()
|
||||||
{
|
{
|
||||||
await Task.Delay(5000);
|
await Task.Delay(5000);
|
||||||
|
|
||||||
@@ -53,9 +53,9 @@ namespace ServiceLib.Services.Statistics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Run()
|
private async Task Run()
|
||||||
{
|
{
|
||||||
Init();
|
await Init();
|
||||||
|
|
||||||
while (!_exitFlag)
|
while (!_exitFlag)
|
||||||
{
|
{
|
||||||
@@ -73,7 +73,7 @@ namespace ServiceLib.Services.Statistics
|
|||||||
{
|
{
|
||||||
webSocket.Abort();
|
webSocket.Abort();
|
||||||
webSocket = null;
|
webSocket = null;
|
||||||
Init();
|
await Init();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace ServiceLib.Services.Statistics
|
|||||||
_exitFlag = true;
|
_exitFlag = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Run()
|
private async Task Run()
|
||||||
{
|
{
|
||||||
while (!_exitFlag)
|
while (!_exitFlag)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -427,22 +427,32 @@ namespace ServiceLib.Services
|
|||||||
{
|
{
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
//Check for standalone windows .Net version
|
var url = RuntimeInformation.ProcessArchitecture switch
|
||||||
if (coreInfo?.CoreType == ECoreType.v2rayN && RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
|
||||||
{
|
|
||||||
var runtimes = await Utils.GetCliWrapOutput("dotnet", "--list-runtimes");
|
|
||||||
if (runtimes == null || runtimes.Contains("Microsoft.WindowsDesktop.App 8") == false)
|
|
||||||
{
|
|
||||||
return coreInfo?.DownloadUrlWin64?.Replace(".zip", "-SelfContained.zip");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RuntimeInformation.ProcessArchitecture switch
|
|
||||||
{
|
{
|
||||||
Architecture.Arm64 => coreInfo?.DownloadUrlWinArm64,
|
Architecture.Arm64 => coreInfo?.DownloadUrlWinArm64,
|
||||||
Architecture.X64 => coreInfo?.DownloadUrlWin64,
|
Architecture.X64 => coreInfo?.DownloadUrlWin64,
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (coreInfo?.CoreType != ECoreType.v2rayN)
|
||||||
|
{
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check for standalone windows .Net version
|
||||||
|
if (File.Exists(Path.Combine(Utils.GetBaseDirectory(), "wpfgfx_cor3.dll"))
|
||||||
|
&& File.Exists(Path.Combine(Utils.GetBaseDirectory(), "D3DCompiler_47_cor3.dll")))
|
||||||
|
{
|
||||||
|
return url?.Replace(".zip", "-SelfContained.zip");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check for avalonia desktop windows version
|
||||||
|
if (File.Exists(Path.Combine(Utils.GetBaseDirectory(), "libHarfBuzzSharp.dll")))
|
||||||
|
{
|
||||||
|
return url?.Replace(".zip", "-desktop.zip");
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
}
|
}
|
||||||
else if (Utils.IsLinux())
|
else if (Utils.IsLinux())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ namespace ServiceLib.ViewModels
|
|||||||
var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}");
|
var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}");
|
||||||
var configDirTemp = Path.Combine(configDirZipTemp, _guiConfigs);
|
var configDirTemp = Path.Combine(configDirZipTemp, _guiConfigs);
|
||||||
|
|
||||||
FileManager.CopyDirectory(configDir, configDirTemp, false, true, "cache.db");
|
FileManager.CopyDirectory(configDir, configDirTemp, false, true, "");
|
||||||
var ret = FileManager.CreateFromDirectory(configDirZipTemp, fileName);
|
var ret = FileManager.CreateFromDirectory(configDirZipTemp, fileName);
|
||||||
Directory.Delete(configDirZipTemp, true);
|
Directory.Delete(configDirZipTemp, true);
|
||||||
return await Task.FromResult(ret);
|
return await Task.FromResult(ret);
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace ServiceLib.ViewModels
|
|||||||
[Reactive] public int SpeedTestTimeout { get; set; }
|
[Reactive] public int SpeedTestTimeout { get; set; }
|
||||||
[Reactive] public string SpeedTestUrl { get; set; }
|
[Reactive] public string SpeedTestUrl { get; set; }
|
||||||
[Reactive] public string SpeedPingTestUrl { get; set; }
|
[Reactive] public string SpeedPingTestUrl { get; set; }
|
||||||
//[Reactive] public int SpeedTestPageSize { get; set; }
|
[Reactive] public int MixedConcurrencyCount { get; set; }
|
||||||
[Reactive] public bool EnableHWA { get; set; }
|
[Reactive] public bool EnableHWA { get; set; }
|
||||||
[Reactive] public string SubConvertUrl { get; set; }
|
[Reactive] public string SubConvertUrl { get; set; }
|
||||||
[Reactive] public int MainGirdOrientation { get; set; }
|
[Reactive] public int MainGirdOrientation { get; set; }
|
||||||
@@ -178,7 +178,7 @@ namespace ServiceLib.ViewModels
|
|||||||
CurrentFontFamily = _config.UiItem.CurrentFontFamily;
|
CurrentFontFamily = _config.UiItem.CurrentFontFamily;
|
||||||
SpeedTestTimeout = _config.SpeedTestItem.SpeedTestTimeout;
|
SpeedTestTimeout = _config.SpeedTestItem.SpeedTestTimeout;
|
||||||
SpeedTestUrl = _config.SpeedTestItem.SpeedTestUrl;
|
SpeedTestUrl = _config.SpeedTestItem.SpeedTestUrl;
|
||||||
//SpeedTestPageSize = _config.SpeedTestItem.SpeedTestPageSize;
|
MixedConcurrencyCount = _config.SpeedTestItem.MixedConcurrencyCount;
|
||||||
SpeedPingTestUrl = _config.SpeedTestItem.SpeedPingTestUrl;
|
SpeedPingTestUrl = _config.SpeedTestItem.SpeedPingTestUrl;
|
||||||
EnableHWA = _config.GuiItem.EnableHWA;
|
EnableHWA = _config.GuiItem.EnableHWA;
|
||||||
SubConvertUrl = _config.ConstItem.SubConvertUrl;
|
SubConvertUrl = _config.ConstItem.SubConvertUrl;
|
||||||
@@ -332,7 +332,7 @@ namespace ServiceLib.ViewModels
|
|||||||
_config.GuiItem.TrayMenuServersLimit = TrayMenuServersLimit;
|
_config.GuiItem.TrayMenuServersLimit = TrayMenuServersLimit;
|
||||||
_config.UiItem.CurrentFontFamily = CurrentFontFamily;
|
_config.UiItem.CurrentFontFamily = CurrentFontFamily;
|
||||||
_config.SpeedTestItem.SpeedTestTimeout = SpeedTestTimeout;
|
_config.SpeedTestItem.SpeedTestTimeout = SpeedTestTimeout;
|
||||||
//_config.SpeedTestItem.SpeedTestPageSize = SpeedTestPageSize;
|
_config.SpeedTestItem.MixedConcurrencyCount = MixedConcurrencyCount;
|
||||||
_config.SpeedTestItem.SpeedTestUrl = SpeedTestUrl;
|
_config.SpeedTestItem.SpeedTestUrl = SpeedTestUrl;
|
||||||
_config.SpeedTestItem.SpeedPingTestUrl = SpeedPingTestUrl;
|
_config.SpeedTestItem.SpeedPingTestUrl = SpeedPingTestUrl;
|
||||||
_config.GuiItem.EnableHWA = EnableHWA;
|
_config.GuiItem.EnableHWA = EnableHWA;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ namespace ServiceLib.ViewModels
|
|||||||
private List<ProfileItem> _lstProfile;
|
private List<ProfileItem> _lstProfile;
|
||||||
private string _serverFilter = string.Empty;
|
private string _serverFilter = string.Empty;
|
||||||
private Dictionary<string, bool> _dicHeaderSort = new();
|
private Dictionary<string, bool> _dicHeaderSort = new();
|
||||||
|
private SpeedtestService? _speedtestService;
|
||||||
|
|
||||||
#endregion private prop
|
#endregion private prop
|
||||||
|
|
||||||
@@ -78,6 +79,7 @@ namespace ServiceLib.ViewModels
|
|||||||
public ReactiveCommand<Unit, Unit> RealPingServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> RealPingServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> SpeedServerCmd { get; }
|
public ReactiveCommand<Unit, Unit> SpeedServerCmd { get; }
|
||||||
public ReactiveCommand<Unit, Unit> SortServerResultCmd { get; }
|
public ReactiveCommand<Unit, Unit> SortServerResultCmd { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> RemoveInvalidServerResultCmd { get; }
|
||||||
|
|
||||||
//servers export
|
//servers export
|
||||||
public ReactiveCommand<Unit, Unit> Export2ClientConfigCmd { get; }
|
public ReactiveCommand<Unit, Unit> Export2ClientConfigCmd { get; }
|
||||||
@@ -196,6 +198,10 @@ namespace ServiceLib.ViewModels
|
|||||||
{
|
{
|
||||||
await SortServer(EServerColName.DelayVal.ToString());
|
await SortServer(EServerColName.DelayVal.ToString());
|
||||||
});
|
});
|
||||||
|
RemoveInvalidServerResultCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await RemoveInvalidServerResult();
|
||||||
|
});
|
||||||
//servers export
|
//servers export
|
||||||
Export2ClientConfigCmd = ReactiveCommand.CreateFromTask(async () =>
|
Export2ClientConfigCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
{
|
{
|
||||||
@@ -268,20 +274,22 @@ namespace ServiceLib.ViewModels
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var item = _profileItems.FirstOrDefault(it => it.IndexId == result.IndexId);
|
var item = _profileItems.FirstOrDefault(it => it.IndexId == result.IndexId);
|
||||||
if (item != null)
|
if (item == null)
|
||||||
{
|
{
|
||||||
if (Utils.IsNotEmpty(result.Delay))
|
return;
|
||||||
{
|
|
||||||
int.TryParse(result.Delay, out int temp);
|
|
||||||
item.Delay = temp;
|
|
||||||
item.DelayVal = $"{result.Delay} {Global.DelayUnit}";
|
|
||||||
}
|
|
||||||
if (Utils.IsNotEmpty(result.Speed))
|
|
||||||
{
|
|
||||||
item.SpeedVal = $"{result.Speed} {Global.SpeedUnit}";
|
|
||||||
}
|
|
||||||
_profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Utils.IsNotEmpty(result.Delay))
|
||||||
|
{
|
||||||
|
int.TryParse(result.Delay, out var temp);
|
||||||
|
item.Delay = temp;
|
||||||
|
item.DelayVal = result.Delay ?? string.Empty;
|
||||||
|
}
|
||||||
|
if (Utils.IsNotEmpty(result.Speed))
|
||||||
|
{
|
||||||
|
item.SpeedVal = result.Speed ?? string.Empty;
|
||||||
|
}
|
||||||
|
_profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateStatistics(ServerSpeedItem update)
|
public void UpdateStatistics(ServerSpeedItem update)
|
||||||
@@ -420,10 +428,11 @@ namespace ServiceLib.ViewModels
|
|||||||
Subid = t.Subid,
|
Subid = t.Subid,
|
||||||
SubRemarks = t.SubRemarks,
|
SubRemarks = t.SubRemarks,
|
||||||
IsActive = t.IndexId == _config.IndexId,
|
IsActive = t.IndexId == _config.IndexId,
|
||||||
Sort = t33 == null ? 0 : t33.Sort,
|
Sort = t33?.Sort ?? 0,
|
||||||
Delay = t33 == null ? 0 : t33.Delay,
|
Delay = t33?.Delay ?? 0,
|
||||||
DelayVal = t33?.Delay != 0 ? $"{t33?.Delay} {Global.DelayUnit}" : string.Empty,
|
Speed = t33?.Speed ?? 0,
|
||||||
SpeedVal = t33?.Speed != 0 ? $"{t33?.Speed} {Global.SpeedUnit}" : string.Empty,
|
DelayVal = t33?.Delay != 0 ? $"{t33?.Delay}" : string.Empty,
|
||||||
|
SpeedVal = t33?.Speed > 0 ? $"{t33?.Speed}" : t33?.Message ?? string.Empty,
|
||||||
TodayDown = t22 == null ? "" : Utils.HumanFy(t22.TodayDown),
|
TodayDown = t22 == null ? "" : Utils.HumanFy(t22.TodayDown),
|
||||||
TodayUp = t22 == null ? "" : Utils.HumanFy(t22.TodayUp),
|
TodayUp = t22 == null ? "" : Utils.HumanFy(t22.TodayUp),
|
||||||
TotalDown = t22 == null ? "" : Utils.HumanFy(t22.TotalDown),
|
TotalDown = t22 == null ? "" : Utils.HumanFy(t22.TotalDown),
|
||||||
@@ -511,7 +520,7 @@ namespace ServiceLib.ViewModels
|
|||||||
}
|
}
|
||||||
var exists = lstSelecteds.Exists(t => t.IndexId == _config.IndexId);
|
var exists = lstSelecteds.Exists(t => t.IndexId == _config.IndexId);
|
||||||
|
|
||||||
await ConfigHandler.RemoveServer(_config, lstSelecteds);
|
await ConfigHandler.RemoveServers(_config, lstSelecteds);
|
||||||
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
|
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
|
||||||
if (lstSelecteds.Count == _profileItems.Count)
|
if (lstSelecteds.Count == _profileItems.Count)
|
||||||
{
|
{
|
||||||
@@ -655,6 +664,13 @@ namespace ServiceLib.ViewModels
|
|||||||
RefreshServers();
|
RefreshServers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task RemoveInvalidServerResult()
|
||||||
|
{
|
||||||
|
var count = await ConfigHandler.RemoveInvalidServerResult(_config, _config.SubIndexId);
|
||||||
|
RefreshServers();
|
||||||
|
NoticeHandler.Instance.Enqueue(string.Format(ResUI.RemoveInvalidServerResultTip, count));
|
||||||
|
}
|
||||||
|
|
||||||
//move server
|
//move server
|
||||||
private async Task MoveToGroup(bool c)
|
private async Task MoveToGroup(bool c)
|
||||||
{
|
{
|
||||||
@@ -722,15 +738,13 @@ namespace ServiceLib.ViewModels
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = new SpeedtestService(_config, actionType, lstSelecteds, (SpeedTestResult result) =>
|
_speedtestService ??= new SpeedtestService(_config, (SpeedTestResult result) => _updateView?.Invoke(EViewAction.DispatcherSpeedTest, result));
|
||||||
{
|
_speedtestService?.RunLoop(actionType, lstSelecteds);
|
||||||
_updateView?.Invoke(EViewAction.DispatcherSpeedTest, result);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ServerSpeedtestStop()
|
public void ServerSpeedtestStop()
|
||||||
{
|
{
|
||||||
MessageBus.Current.SendMessage("", EMsgCommand.StopSpeedtest.ToString());
|
_speedtestService?.ExitLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Export2ClientConfigAsync(bool blClipboard)
|
private async Task Export2ClientConfigAsync(bool blClipboard)
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ namespace ServiceLib.ViewModels
|
|||||||
[Reactive]
|
[Reactive]
|
||||||
public int SystemProxySelected { get; set; }
|
public int SystemProxySelected { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public bool BlSystemProxyPacVisible { get; set; }
|
||||||
|
|
||||||
#endregion System Proxy
|
#endregion System Proxy
|
||||||
|
|
||||||
#region UI
|
#region UI
|
||||||
@@ -96,6 +99,7 @@ namespace ServiceLib.ViewModels
|
|||||||
SelectedRouting = new();
|
SelectedRouting = new();
|
||||||
SelectedServer = new();
|
SelectedServer = new();
|
||||||
RunningServerToolTipText = "-";
|
RunningServerToolTipText = "-";
|
||||||
|
BlSystemProxyPacVisible = Utils.IsWindows();
|
||||||
|
|
||||||
if (_config.TunModeItem.EnableTun && AllowEnableTun())
|
if (_config.TunModeItem.EnableTun && AllowEnableTun())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceInclude Source="Assets/GlobalResources.axaml" />
|
<ResourceInclude Source="Assets/GlobalResources.axaml" />
|
||||||
|
<ResourceInclude Source="Controls/AutoCompleteBox.axaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
@@ -46,6 +47,12 @@
|
|||||||
Header="{x:Static resx:ResUI.menuSystemProxyNothing}"
|
Header="{x:Static resx:ResUI.menuSystemProxyNothing}"
|
||||||
IsChecked="{Binding BlSystemProxyNothing}"
|
IsChecked="{Binding BlSystemProxyNothing}"
|
||||||
ToggleType="Radio" />
|
ToggleType="Radio" />
|
||||||
|
<NativeMenuItem
|
||||||
|
Command="{Binding SystemProxyPacCmd}"
|
||||||
|
Header="{x:Static resx:ResUI.menuSystemProxyPac}"
|
||||||
|
IsChecked="{Binding BlSystemProxyPac}"
|
||||||
|
IsVisible="{Binding BlSystemProxyPacVisible}"
|
||||||
|
ToggleType="Radio" />
|
||||||
<NativeMenuItemSeparator />
|
<NativeMenuItemSeparator />
|
||||||
<NativeMenuItem Click="MenuAddServerViaClipboardClick" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" />
|
<NativeMenuItem Click="MenuAddServerViaClipboardClick" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" />
|
||||||
<NativeMenuItem Header="{x:Static resx:ResUI.menuAddServerViaScan}" IsVisible="False" />
|
<NativeMenuItem Header="{x:Static resx:ResUI.menuAddServerViaScan}" IsVisible="False" />
|
||||||
@@ -61,4 +68,4 @@
|
|||||||
</TrayIcon>
|
</TrayIcon>
|
||||||
</TrayIcons>
|
</TrayIcons>
|
||||||
</TrayIcon.Icons>
|
</TrayIcon.Icons>
|
||||||
</Application>
|
</Application>
|
||||||
|
|||||||
@@ -20,4 +20,7 @@
|
|||||||
<Style Selector="Grid.Margin8">
|
<Style Selector="Grid.Margin8">
|
||||||
<Setter Property="Margin" Value="8" />
|
<Setter Property="Margin" Value="8" />
|
||||||
</Style>
|
</Style>
|
||||||
</Styles>
|
<Style Selector="DataGrid">
|
||||||
|
<Setter Property="RowHeight" Value="24" />
|
||||||
|
</Style>
|
||||||
|
</Styles>
|
||||||
|
|||||||
48
v2rayN/v2rayN.Desktop/Controls/AutoCompleteBox.axaml
Normal file
48
v2rayN/v2rayN.Desktop/Controls/AutoCompleteBox.axaml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<ResourceDictionary
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:controls="clr-namespace:v2rayN.Desktop.Controls">
|
||||||
|
<!-- Add Resources Here -->
|
||||||
|
<ControlTheme x:Key="{x:Type controls:AutoCompleteBox}" TargetType="controls:AutoCompleteBox">
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
|
<Setter Property="MinHeight" Value="{DynamicResource AutoCompleteBoxDefaultHeight}" />
|
||||||
|
<Setter Property="MaxDropDownHeight" Value="{DynamicResource AutoCompleteMaxDropdownHeight}" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<ControlTemplate TargetType="AutoCompleteBox">
|
||||||
|
<Panel>
|
||||||
|
<TextBox
|
||||||
|
Name="PART_TextBox"
|
||||||
|
MinHeight="{TemplateBinding MinHeight}"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}"
|
||||||
|
InnerLeftContent="{TemplateBinding InnerLeftContent}"
|
||||||
|
InnerRightContent="{TemplateBinding InnerRightContent}"
|
||||||
|
Watermark="{TemplateBinding Watermark}" />
|
||||||
|
<Popup
|
||||||
|
Name="PART_Popup"
|
||||||
|
MaxHeight="{TemplateBinding MaxDropDownHeight}"
|
||||||
|
IsLightDismissEnabled="True"
|
||||||
|
PlacementTarget="{TemplateBinding}">
|
||||||
|
<Border
|
||||||
|
MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}"
|
||||||
|
Margin="{DynamicResource AutoCompleteBoxPopupMargin}"
|
||||||
|
Padding="{DynamicResource AutoCompleteBoxPopupPadding}"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Background="{DynamicResource AutoCompleteBoxPopupBackground}"
|
||||||
|
BorderBrush="{DynamicResource AutoCompleteBoxPopupBorderBrush}"
|
||||||
|
BorderThickness="{DynamicResource AutoCompleteBoxPopupBorderThickness}"
|
||||||
|
BoxShadow="{DynamicResource AutoCompleteBoxPopupBoxShadow}"
|
||||||
|
CornerRadius="{DynamicResource AutoCompleteBoxPopupCornerRadius}">
|
||||||
|
<ListBox
|
||||||
|
Name="PART_SelectingItemsControl"
|
||||||
|
Foreground="{TemplateBinding Foreground}"
|
||||||
|
ItemTemplate="{TemplateBinding ItemTemplate}"
|
||||||
|
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
||||||
|
ScrollViewer.VerticalScrollBarVisibility="Auto" />
|
||||||
|
</Border>
|
||||||
|
</Popup>
|
||||||
|
</Panel>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter>
|
||||||
|
</ControlTheme>
|
||||||
|
</ResourceDictionary>
|
||||||
38
v2rayN/v2rayN.Desktop/Controls/AutoCompleteBox.cs
Normal file
38
v2rayN/v2rayN.Desktop/Controls/AutoCompleteBox.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
|
||||||
|
namespace v2rayN.Desktop.Controls;
|
||||||
|
|
||||||
|
public class AutoCompleteBox : Avalonia.Controls.AutoCompleteBox
|
||||||
|
{
|
||||||
|
static AutoCompleteBox()
|
||||||
|
{
|
||||||
|
MinimumPrefixLengthProperty.OverrideDefaultValue<AutoCompleteBox>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutoCompleteBox()
|
||||||
|
{
|
||||||
|
AddHandler(PointerPressedEvent, OnBoxPointerPressed, RoutingStrategies.Tunnel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBoxPointerPressed(object? sender, PointerPressedEventArgs e)
|
||||||
|
{
|
||||||
|
if (Equals(sender, this) && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||||
|
{
|
||||||
|
SetCurrentValue(IsDropDownOpenProperty, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnGotFocus(GotFocusEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnGotFocus(e);
|
||||||
|
if (IsDropDownOpen)
|
||||||
|
return;
|
||||||
|
SetCurrentValue(IsDropDownOpenProperty, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
SetCurrentValue(SelectedItemProperty, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -119,6 +119,17 @@ namespace v2rayN.Desktop.ViewModels
|
|||||||
Value = size,
|
Value = size,
|
||||||
});
|
});
|
||||||
Application.Current?.Styles.Add(style);
|
Application.Current?.Styles.Add(style);
|
||||||
|
|
||||||
|
ModifyFontSizeEx(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ModifyFontSizeEx(double size)
|
||||||
|
{
|
||||||
|
//DataGrid
|
||||||
|
var rowHeight = 20 + (size / 2);
|
||||||
|
var style = new Style(x => x.OfType<DataGrid>());
|
||||||
|
style.Add(new Setter(DataGrid.RowHeightProperty, rowHeight));
|
||||||
|
Application.Current?.Styles.Add(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ModifyFontFamily()
|
private void ModifyFontFamily()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
xmlns:view="using:v2rayN.Desktop.Views"
|
xmlns:view="using:v2rayN.Desktop.Views"
|
||||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||||
Title="v2rayN"
|
Title="v2rayN"
|
||||||
Width="900"
|
Width="1000"
|
||||||
Height="600"
|
Height="600"
|
||||||
MinWidth="900"
|
MinWidth="900"
|
||||||
x:DataType="vms:MainWindowViewModel"
|
x:DataType="vms:MainWindowViewModel"
|
||||||
@@ -166,4 +166,4 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</dialogHost:DialogHost>
|
</dialogHost:DialogHost>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@@ -414,18 +414,17 @@ namespace v2rayN.Desktop.Views
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Utils.IsOSX() || _config.UiItem.Hide2TrayWhenClose)
|
if (Utils.IsLinux() && _config.UiItem.Hide2TrayWhenClose == false)
|
||||||
{
|
|
||||||
foreach (var ownedWindow in this.OwnedWindows)
|
|
||||||
{
|
|
||||||
ownedWindow.Close();
|
|
||||||
}
|
|
||||||
this.Hide();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
this.WindowState = WindowState.Minimized;
|
this.WindowState = WindowState.Minimized;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var ownedWindow in this.OwnedWindows)
|
||||||
|
{
|
||||||
|
ownedWindow.Close();
|
||||||
|
}
|
||||||
|
this.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
_config.UiItem.ShowInTaskbar = bl;
|
_config.UiItem.ShowInTaskbar = bl;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
x:Class="v2rayN.Desktop.Views.OptionSettingWindow"
|
x:Class="v2rayN.Desktop.Views.OptionSettingWindow"
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:ctrls="clr-namespace:v2rayN.Desktop.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
@@ -219,8 +220,7 @@
|
|||||||
Grid.Row="13"
|
Grid.Row="13"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Classes="Margin8"
|
Classes="Margin8" />
|
||||||
ToolTip.Tip="Level" />
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="14"
|
Grid.Row="14"
|
||||||
@@ -459,6 +459,7 @@
|
|||||||
Classes="Margin8" />
|
Classes="Margin8" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
x:Name="labHide2TrayWhenClose"
|
||||||
Grid.Row="9"
|
Grid.Row="9"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
@@ -504,13 +505,12 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Classes="Margin8"
|
Classes="Margin8"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamily}" />
|
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamily}" />
|
||||||
<ComboBox
|
<ctrls:AutoCompleteBox
|
||||||
x:Name="cmbcurrentFontFamily"
|
x:Name="cmbcurrentFontFamily"
|
||||||
Grid.Row="15"
|
Grid.Row="15"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="300"
|
||||||
Classes="Margin8"
|
Classes="Margin8" />
|
||||||
MaxDropDownHeight="1000" />
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="15"
|
Grid.Row="15"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
@@ -518,21 +518,20 @@
|
|||||||
Classes="Margin8"
|
Classes="Margin8"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyLinuxTip}"
|
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyLinuxTip}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<!--
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="16"
|
Grid.Row="16"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Classes="Margin8"
|
Classes="Margin8"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSpeedTestPageSize}" />
|
Text="{x:Static resx:ResUI.TbSettingsMixedConcurrencyCount}" />
|
||||||
<TextBox
|
<ComboBox
|
||||||
x:Name="txtSpeedTestPageSize"
|
x:Name="cmbMixedConcurrencyCount"
|
||||||
Grid.Row="16"
|
Grid.Row="16"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Classes="Margin8" />
|
Classes="Margin8" />
|
||||||
-->
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="17"
|
Grid.Row="17"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
@@ -552,8 +551,8 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Classes="Margin8"
|
Classes="Margin8"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSpeedTestUrl}" />
|
Text="{x:Static resx:ResUI.TbSettingsSpeedTestUrl}" />
|
||||||
<ComboBox
|
<ctrls:AutoCompleteBox
|
||||||
x:Name="cmbSpeedTestUrl"
|
Name="cmbSpeedTestUrl"
|
||||||
Grid.Row="18"
|
Grid.Row="18"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
@@ -565,7 +564,7 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Classes="Margin8"
|
Classes="Margin8"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSpeedPingTestUrl}" />
|
Text="{x:Static resx:ResUI.TbSettingsSpeedPingTestUrl}" />
|
||||||
<ComboBox
|
<ctrls:AutoCompleteBox
|
||||||
x:Name="cmbSpeedPingTestUrl"
|
x:Name="cmbSpeedPingTestUrl"
|
||||||
Grid.Row="19"
|
Grid.Row="19"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
@@ -578,13 +577,12 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Classes="Margin8"
|
Classes="Margin8"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
||||||
<ComboBox
|
<ctrls:AutoCompleteBox
|
||||||
x:Name="cmbSubConvertUrl"
|
x:Name="cmbSubConvertUrl"
|
||||||
Grid.Row="20"
|
Grid.Row="20"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="300"
|
||||||
Classes="Margin8"
|
Classes="Margin8" />
|
||||||
ToolTip.Tip="Convert Url" />
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="21"
|
Grid.Row="21"
|
||||||
@@ -596,7 +594,7 @@
|
|||||||
x:Name="cmbMainGirdOrientation"
|
x:Name="cmbMainGirdOrientation"
|
||||||
Grid.Row="21"
|
Grid.Row="21"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="200"
|
||||||
Classes="Margin8" />
|
Classes="Margin8" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
@@ -687,8 +685,7 @@
|
|||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbsystemProxyAdvancedProtocol"
|
x:Name="cmbsystemProxyAdvancedProtocol"
|
||||||
MinWidth="400"
|
MinWidth="400"
|
||||||
Classes="Margin8"
|
Classes="Margin8" />
|
||||||
ToolTip.Tip="Protocol" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
@@ -788,6 +785,7 @@
|
|||||||
Classes="Margin8" />
|
Classes="Margin8" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
x:Name="labLinuxSudoPassword"
|
||||||
Grid.Row="7"
|
Grid.Row="7"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
@@ -801,6 +799,7 @@
|
|||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Classes="Margin8" />
|
Classes="Margin8" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
x:Name="labLinuxSudoPasswordTip"
|
||||||
Grid.Row="7"
|
Grid.Row="7"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|||||||
@@ -66,22 +66,19 @@ namespace v2rayN.Desktop.Views
|
|||||||
cmbCoreType6.Items.Add(it);
|
cmbCoreType6.Items.Add(it);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (int i = 2; i <= 6; i++)
|
for (var i = 2; i <= 8; i++)
|
||||||
|
{
|
||||||
|
cmbMixedConcurrencyCount.Items.Add(i);
|
||||||
|
}
|
||||||
|
for (var i = 2; i <= 6; i++)
|
||||||
{
|
{
|
||||||
cmbSpeedTestTimeout.Items.Add(i * 5);
|
cmbSpeedTestTimeout.Items.Add(i * 5);
|
||||||
}
|
}
|
||||||
Global.SpeedTestUrls.ForEach(it =>
|
|
||||||
{
|
cmbSpeedTestUrl.ItemsSource = Global.SpeedTestUrls;
|
||||||
cmbSpeedTestUrl.Items.Add(it);
|
cmbSpeedPingTestUrl.ItemsSource = Global.SpeedPingTestUrls;
|
||||||
});
|
cmbSubConvertUrl.ItemsSource = Global.SubConvertUrls;
|
||||||
Global.SpeedPingTestUrls.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbSpeedPingTestUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.SubConvertUrls.ForEach(it =>
|
|
||||||
{
|
|
||||||
cmbSubConvertUrl.Items.Add(it);
|
|
||||||
});
|
|
||||||
Global.GeoFilesSources.ForEach(it =>
|
Global.GeoFilesSources.ForEach(it =>
|
||||||
{
|
{
|
||||||
cmbGetFilesSourceUrl.Items.Add(it);
|
cmbGetFilesSourceUrl.Items.Add(it);
|
||||||
@@ -135,12 +132,12 @@ namespace v2rayN.Desktop.Views
|
|||||||
this.Bind(ViewModel, vm => vm.Hide2TrayWhenClose, v => v.togHide2TrayWhenClose.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.Hide2TrayWhenClose, v => v.togHide2TrayWhenClose.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.AutoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.AutoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CurrentFontFamily, v => v.cmbcurrentFontFamily.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CurrentFontFamily, v => v.cmbcurrentFontFamily.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SpeedTestTimeout, v => v.cmbSpeedTestTimeout.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SpeedTestTimeout, v => v.cmbSpeedTestTimeout.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SpeedTestUrl, v => v.cmbSpeedTestUrl.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SpeedTestUrl, v => v.cmbSpeedTestUrl.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SpeedPingTestUrl, v => v.cmbSpeedPingTestUrl.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SpeedPingTestUrl, v => v.cmbSpeedPingTestUrl.Text).DisposeWith(disposables);
|
||||||
//this.Bind(ViewModel, vm => vm.SpeedTestPageSize, v => v.txtSpeedTestPageSize.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.MixedConcurrencyCount, v => v.cmbMixedConcurrencyCount.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SubConvertUrl, v => v.cmbSubConvertUrl.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SubConvertUrl, v => v.cmbSubConvertUrl.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.MainGirdOrientation, v => v.cmbMainGirdOrientation.SelectedIndex).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.MainGirdOrientation, v => v.cmbMainGirdOrientation.SelectedIndex).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||||
@@ -170,12 +167,27 @@ namespace v2rayN.Desktop.Views
|
|||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
txbSettingsExceptionTip2.IsVisible = false;
|
txbSettingsExceptionTip2.IsVisible = false;
|
||||||
|
|
||||||
|
txtLinuxSudoPassword.IsVisible = false;
|
||||||
|
labLinuxSudoPassword.IsVisible = false;
|
||||||
|
labLinuxSudoPasswordTip.IsVisible = false;
|
||||||
|
|
||||||
|
labHide2TrayWhenClose.IsVisible = false;
|
||||||
|
togHide2TrayWhenClose.IsVisible = false;
|
||||||
}
|
}
|
||||||
else
|
else if (Utils.IsLinux())
|
||||||
{
|
{
|
||||||
txbSettingsExceptionTip.IsVisible = false;
|
txbSettingsExceptionTip.IsVisible = false;
|
||||||
panSystemProxyAdvanced.IsVisible = false;
|
panSystemProxyAdvanced.IsVisible = false;
|
||||||
}
|
}
|
||||||
|
else if (Utils.IsOSX())
|
||||||
|
{
|
||||||
|
txbSettingsExceptionTip.IsVisible = false;
|
||||||
|
panSystemProxyAdvanced.IsVisible = false;
|
||||||
|
|
||||||
|
labHide2TrayWhenClose.IsVisible = false;
|
||||||
|
togHide2TrayWhenClose.IsVisible = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||||
@@ -196,8 +208,9 @@ namespace v2rayN.Desktop.Views
|
|||||||
private async Task InitSettingFont()
|
private async Task InitSettingFont()
|
||||||
{
|
{
|
||||||
var lstFonts = await GetFonts();
|
var lstFonts = await GetFonts();
|
||||||
lstFonts.ForEach(it => { cmbcurrentFontFamily.Items.Add(it); });
|
|
||||||
cmbcurrentFontFamily.Items.Add(string.Empty);
|
lstFonts.Add(string.Empty);
|
||||||
|
cmbcurrentFontFamily.ItemsSource = lstFonts;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<string>> GetFonts()
|
private async Task<List<string>> GetFonts()
|
||||||
|
|||||||
@@ -84,10 +84,12 @@
|
|||||||
<DataGrid
|
<DataGrid
|
||||||
x:Name="lstProfiles"
|
x:Name="lstProfiles"
|
||||||
AutoGenerateColumns="False"
|
AutoGenerateColumns="False"
|
||||||
|
CanUserReorderColumns="True"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CanUserResizeColumns="True"
|
CanUserResizeColumns="True"
|
||||||
GridLinesVisibility="All"
|
GridLinesVisibility="All"
|
||||||
HeadersVisibility="All"
|
HeadersVisibility="All"
|
||||||
|
ScrollViewer.AllowAutoHide="False"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
ItemsSource="{Binding ProfileItems}">
|
ItemsSource="{Binding ProfileItems}">
|
||||||
<DataGrid.KeyBindings>
|
<DataGrid.KeyBindings>
|
||||||
@@ -104,14 +106,16 @@
|
|||||||
<MenuItem x:Name="menuShareServer" Header="{x:Static resx:ResUI.menuShareServer}" />
|
<MenuItem x:Name="menuShareServer" Header="{x:Static resx:ResUI.menuShareServer}" />
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem x:Name="menuSetDefaultMultipleServer" Header="{x:Static resx:ResUI.menuSetDefaultMultipleServer}" />
|
<MenuItem x:Name="menuSetDefaultMultipleServer" Header="{x:Static resx:ResUI.menuSetDefaultMultipleServer}" />
|
||||||
|
|
||||||
<MenuItem x:Name="menuSetDefaultLoadBalanceServer" Header="{x:Static resx:ResUI.menuSetDefaultLoadBalanceServer}" />
|
<MenuItem x:Name="menuSetDefaultLoadBalanceServer" Header="{x:Static resx:ResUI.menuSetDefaultLoadBalanceServer}" />
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem x:Name="menuMixedTestServer" Header="{x:Static resx:ResUI.menuMixedTestServer}" />
|
<MenuItem x:Name="menuMixedTestServer" Header="{x:Static resx:ResUI.menuMixedTestServer}" />
|
||||||
<MenuItem x:Name="menuTcpingServer" Header="{x:Static resx:ResUI.menuTcpingServer}" />
|
<MenuItem x:Name="menuTcpingServer" Header="{x:Static resx:ResUI.menuTcpingServer}" />
|
||||||
<MenuItem x:Name="menuRealPingServer" Header="{x:Static resx:ResUI.menuRealPingServer}" />
|
<MenuItem x:Name="menuRealPingServer" Header="{x:Static resx:ResUI.menuRealPingServer}" />
|
||||||
<MenuItem x:Name="menuSpeedServer" Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
<MenuItem x:Name="menuSpeedServer" Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
||||||
<MenuItem x:Name="menuSortServerResult" Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
<MenuItem Header="{x:Static resx:ResUI.menuTestServerResult}">
|
||||||
|
<MenuItem x:Name="menuSortServerResult" Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
||||||
|
<MenuItem x:Name="menuRemoveInvalidServerResult" Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" />
|
||||||
|
</MenuItem>
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem x:Name="menuMoveToGroup" Header="{x:Static resx:ResUI.menuMoveToGroup}">
|
<MenuItem x:Name="menuMoveToGroup" Header="{x:Static resx:ResUI.menuMoveToGroup}">
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
@@ -245,4 +249,4 @@
|
|||||||
</DataGrid>
|
</DataGrid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ namespace v2rayN.Desktop.Views
|
|||||||
this.BindCommand(ViewModel, vm => vm.RealPingServerCmd, v => v.menuRealPingServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.RealPingServerCmd, v => v.menuRealPingServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.RemoveInvalidServerResultCmd, v => v.menuRemoveInvalidServerResult).DisposeWith(disposables);
|
||||||
|
|
||||||
//servers export
|
//servers export
|
||||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigClipboardCmd, v => v.menuExport2ClientConfigClipboard).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigClipboardCmd, v => v.menuExport2ClientConfigClipboard).DisposeWith(disposables);
|
||||||
@@ -371,9 +372,8 @@ namespace v2rayN.Desktop.Views
|
|||||||
private void StorageUI(string? n = null)
|
private void StorageUI(string? n = null)
|
||||||
{
|
{
|
||||||
List<ColumnItem> lvColumnItem = new();
|
List<ColumnItem> lvColumnItem = new();
|
||||||
for (int k = 0; k < lstProfiles.Columns.Count; k++)
|
foreach (var item2 in lstProfiles.Columns)
|
||||||
{
|
{
|
||||||
var item2 = lstProfiles.Columns[k];
|
|
||||||
if (item2.Tag == null)
|
if (item2.Tag == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" />
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" />
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxySet}" />
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxySet}" />
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyNothing}" />
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyNothing}" />
|
||||||
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyPac}" />
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
|
|
||||||
<ComboBox
|
<ComboBox
|
||||||
@@ -78,4 +79,4 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ namespace v2rayN.Desktop.Views
|
|||||||
});
|
});
|
||||||
|
|
||||||
//spEnableTun.IsVisible = (Utils.IsWindows() || AppHandler.Instance.IsAdministrator);
|
//spEnableTun.IsVisible = (Utils.IsWindows() || AppHandler.Instance.IsAdministrator);
|
||||||
|
|
||||||
|
if (Utils.IsNonWindows() && cmbSystemProxy.Items.IsReadOnly == false)
|
||||||
|
{
|
||||||
|
cmbSystemProxy.Items.RemoveAt(cmbSystemProxy.Items.Count - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||||
|
|||||||
@@ -764,7 +764,7 @@
|
|||||||
x:Name="cmbcurrentFontFamily"
|
x:Name="cmbcurrentFontFamily"
|
||||||
Grid.Row="15"
|
Grid.Row="15"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="300"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
MaxDropDownHeight="1000"
|
MaxDropDownHeight="1000"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
@@ -776,23 +776,22 @@
|
|||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyTip}"
|
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyTip}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<!--
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="16"
|
Grid.Row="16"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsSpeedTestPageSize}" />
|
Text="{x:Static resx:ResUI.TbSettingsMixedConcurrencyCount}" />
|
||||||
<TextBox
|
<ComboBox
|
||||||
x:Name="txtSpeedTestPageSize"
|
x:Name="cmbMixedConcurrencyCount"
|
||||||
Grid.Row="16"
|
Grid.Row="16"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
HorizontalAlignment="Left"
|
Style="{StaticResource DefComboBox}" />
|
||||||
Style="{StaticResource DefTextBox}" />
|
|
||||||
-->
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="17"
|
Grid.Row="17"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
@@ -868,7 +867,7 @@
|
|||||||
x:Name="cmbMainGirdOrientation"
|
x:Name="cmbMainGirdOrientation"
|
||||||
Grid.Row="21"
|
Grid.Row="21"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="300"
|
Width="200"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,11 @@ namespace v2rayN.Views
|
|||||||
cmbCoreType6.Items.Add(it);
|
cmbCoreType6.Items.Add(it);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (int i = 2; i <= 6; i++)
|
for (var i = 2; i <= 8; i++)
|
||||||
|
{
|
||||||
|
cmbMixedConcurrencyCount.Items.Add(i);
|
||||||
|
}
|
||||||
|
for (var i = 2; i <= 6; i++)
|
||||||
{
|
{
|
||||||
cmbSpeedTestTimeout.Items.Add(i * 5);
|
cmbSpeedTestTimeout.Items.Add(i * 5);
|
||||||
}
|
}
|
||||||
@@ -150,7 +154,7 @@ namespace v2rayN.Views
|
|||||||
this.Bind(ViewModel, vm => vm.SpeedTestTimeout, v => v.cmbSpeedTestTimeout.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SpeedTestTimeout, v => v.cmbSpeedTestTimeout.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SpeedTestUrl, v => v.cmbSpeedTestUrl.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SpeedTestUrl, v => v.cmbSpeedTestUrl.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SpeedPingTestUrl, v => v.cmbSpeedPingTestUrl.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SpeedPingTestUrl, v => v.cmbSpeedPingTestUrl.Text).DisposeWith(disposables);
|
||||||
//this.Bind(ViewModel, vm => vm.SpeedTestPageSize, v => v.txtSpeedTestPageSize.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.MixedConcurrencyCount, v => v.cmbMixedConcurrencyCount.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.EnableHWA, v => v.togEnableHWA.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.EnableHWA, v => v.togEnableHWA.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SubConvertUrl, v => v.cmbSubConvertUrl.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SubConvertUrl, v => v.cmbSubConvertUrl.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.MainGirdOrientation, v => v.cmbMainGirdOrientation.SelectedIndex).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.MainGirdOrientation, v => v.cmbMainGirdOrientation.SelectedIndex).DisposeWith(disposables);
|
||||||
|
|||||||
@@ -146,10 +146,16 @@
|
|||||||
x:Name="menuSpeedServer"
|
x:Name="menuSpeedServer"
|
||||||
Height="{StaticResource MenuItemHeight}"
|
Height="{StaticResource MenuItemHeight}"
|
||||||
Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
||||||
<MenuItem
|
<MenuItem Header="{x:Static resx:ResUI.menuTestServerResult}">
|
||||||
x:Name="menuSortServerResult"
|
<MenuItem
|
||||||
Height="{StaticResource MenuItemHeight}"
|
x:Name="menuSortServerResult"
|
||||||
Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
||||||
|
<MenuItem
|
||||||
|
x:Name="menuRemoveInvalidServerResult"
|
||||||
|
Height="{StaticResource MenuItemHeight}"
|
||||||
|
Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" />
|
||||||
|
</MenuItem>
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
x:Name="menuMoveToGroup"
|
x:Name="menuMoveToGroup"
|
||||||
@@ -321,4 +327,4 @@
|
|||||||
</DataGrid>
|
</DataGrid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</reactiveui:ReactiveUserControl>
|
</reactiveui:ReactiveUserControl>
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ namespace v2rayN.Views
|
|||||||
this.BindCommand(ViewModel, vm => vm.RealPingServerCmd, v => v.menuRealPingServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.RealPingServerCmd, v => v.menuRealPingServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.RemoveInvalidServerResultCmd, v => v.menuRemoveInvalidServerResult).DisposeWith(disposables);
|
||||||
|
|
||||||
//servers export
|
//servers export
|
||||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
||||||
@@ -352,9 +353,9 @@ namespace v2rayN.Views
|
|||||||
private void StorageUI(string? n = null)
|
private void StorageUI(string? n = null)
|
||||||
{
|
{
|
||||||
List<ColumnItem> lvColumnItem = new();
|
List<ColumnItem> lvColumnItem = new();
|
||||||
for (int k = 0; k < lstProfiles.Columns.Count; k++)
|
foreach (var t in lstProfiles.Columns)
|
||||||
{
|
{
|
||||||
var item2 = (MyDGTextColumn)lstProfiles.Columns[k];
|
var item2 = (MyDGTextColumn)t;
|
||||||
lvColumnItem.Add(new()
|
lvColumnItem.Add(new()
|
||||||
{
|
{
|
||||||
Name = item2.ExName,
|
Name = item2.ExName,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<reactiveui:ReactiveUserControl
|
<reactiveui:ReactiveUserControl
|
||||||
x:Class="v2rayN.Views.StatusBarView"
|
x:Class="v2rayN.Views.StatusBarView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
@@ -102,11 +102,9 @@
|
|||||||
|
|
||||||
<tb:TaskbarIcon
|
<tb:TaskbarIcon
|
||||||
x:Name="tbNotify"
|
x:Name="tbNotify"
|
||||||
|
IconSource="/Resources/v2rayN.ico"
|
||||||
NoLeftClickDelay="True"
|
NoLeftClickDelay="True"
|
||||||
ToolTipText="v2rayN">
|
ToolTipText="v2rayN">
|
||||||
<tb:TaskbarIcon.IconSource>
|
|
||||||
<tb:GeneratedIconSource Foreground="Red" Text="❤️" />
|
|
||||||
</tb:TaskbarIcon.IconSource>
|
|
||||||
<tb:TaskbarIcon.ContextMenu>
|
<tb:TaskbarIcon.ContextMenu>
|
||||||
<ContextMenu Style="{StaticResource DefContextMenu}">
|
<ContextMenu Style="{StaticResource DefContextMenu}">
|
||||||
<MenuItem x:Name="menuSystemProxyClear" Height="{StaticResource MenuItemHeight}">
|
<MenuItem x:Name="menuSystemProxyClear" Height="{StaticResource MenuItemHeight}">
|
||||||
@@ -215,4 +213,4 @@
|
|||||||
</tb:TaskbarIcon.ContextMenu>
|
</tb:TaskbarIcon.ContextMenu>
|
||||||
</tb:TaskbarIcon>
|
</tb:TaskbarIcon>
|
||||||
</Grid>
|
</Grid>
|
||||||
</reactiveui:ReactiveUserControl>
|
</reactiveui:ReactiveUserControl>
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ namespace v2rayN.Views
|
|||||||
this.OneWayBind(ViewModel, vm => vm.BlSystemProxyPac, v => v.menuSystemProxyPac2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables);
|
this.OneWayBind(ViewModel, vm => vm.BlSystemProxyPac, v => v.menuSystemProxyPac2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SystemProxyClearCmd, v => v.menuSystemProxyClear).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SystemProxyClearCmd, v => v.menuSystemProxyClear).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SystemProxySetCmd, v => v.menuSystemProxySet).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SystemProxySetCmd, v => v.menuSystemProxySet).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SystemProxyPacCmd, v => v.menuSystemProxyPac).DisposeWith(disposables);
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SystemProxyNothingCmd, v => v.menuSystemProxyNothing).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SystemProxyNothingCmd, v => v.menuSystemProxyNothing).DisposeWith(disposables);
|
||||||
|
this.BindCommand(ViewModel, vm => vm.SystemProxyPacCmd, v => v.menuSystemProxyPac).DisposeWith(disposables);
|
||||||
|
|
||||||
//routings and servers
|
//routings and servers
|
||||||
this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings.ItemsSource).DisposeWith(disposables);
|
this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings.ItemsSource).DisposeWith(disposables);
|
||||||
|
|||||||
Reference in New Issue
Block a user