Compare commits

...

8 Commits

Author SHA1 Message Date
2dust 984c77f0c4 up 7.24.1 2026-07-17 09:26:10 +08:00
2dust b5e0be47a5 Code clean 2026-07-17 09:25:13 +08:00
dependabot[bot] 6df0e6de1b Bump actions/setup-dotnet from 5.4.0 to 6.0.0 (#9778)
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 5.4.0 to 6.0.0.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v5.4.0...v6.0.0)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-17 09:13:28 +08:00
autorepobot 2b5328665f Update package-rhel.sh (#9780)
* Update package-rhel.sh

* Update package-rhel-riscv.sh

* Update package-rhel-loong.sh

* Update package-debian.sh

* Update package-debian-riscv.sh

* Update package-debian-loong.sh

* Update package-debian-riscv.sh

* Update package-rhel-riscv.sh
2026-07-17 09:13:19 +08:00
DHR60 4584ecc5c9 Add HappyEyeballs (#9772)
* Add HappyEyeballs

* Clean up the code

* Fix
2026-07-17 09:12:50 +08:00
DHR60 d9dc2d7cf5 Fix (#9776) 2026-07-17 09:11:28 +08:00
DHR60 36f8565b7a Update cert (#9773) 2026-07-17 08:59:30 +08:00
DHR60 f55d8b2565 Sync xray (#9708)
* Sync xray fragment

* Sync xray freedom domainStrategy

* Add Strategy4ProxyDial
2026-07-16 18:55:06 +08:00
37 changed files with 2802 additions and 3820 deletions
+53 -52
View File
@@ -1,3 +1,49 @@
/*
==============================================================================
THIRD-PARTY CA CERTIFICATE DATA ATTRIBUTION
==============================================================================
This component includes CA certificate data obtained from third-party sources.
1. Common CA Database (CCADB)
------------------------------------------------------------------------------
Website:
https://www.ccadb.org/
Data source:
https://ccadb.my.salesforce-sites.com/mozilla/IncludedRootsPEMTxt?TrustBitsInclude=Websites
License:
Community Data License Agreement – Permissive, Version 2.0 (CDLA-2.0 Permissive)
The names and trademarks of CCADB contributors may not be used to endorse or
promote products derived from this data without prior written permission.
License text:
https://cdla.dev/permissive-2-0/
2. Chromium Root Store
------------------------------------------------------------------------------
Source:
Chromium Project
Data source:
https://chromium.googlesource.com/chromium/src/+/main/net/data/ssl/chrome_root_store/root_store.certs?format=TEXT
License:
BSD 3-Clause License
Copyright:
Copyright (c) The Chromium Authors
The Chromium Root Store data is distributed under the BSD 3-Clause License.
License text:
https://opensource.org/licenses/BSD-3-Clause
==============================================================================
*/
using System; using System;
using System.Net.Http; using System.Net.Http;
using System.Text; using System.Text;
@@ -27,68 +73,23 @@ Console.WriteLine("\nAll done!");
async Task ProcessMozillaAsync(string outputDir) async Task ProcessMozillaAsync(string outputDir)
{ {
const string certdataUrl = "https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/release/security/nss/lib/ckfw/builtins/certdata.txt"; const string certdataUrl = "https://ccadb.my.salesforce-sites.com/mozilla/IncludedRootsPEMTxt?TrustBitsInclude=Websites";
var outputFile = Path.Combine(outputDir, "mozilla_roots_pem"); var outputFile = Path.Combine(outputDir, "mozilla_roots_pem");
Console.WriteLine("Downloading Mozilla certdata.txt..."); Console.WriteLine("Downloading Mozilla certdata.txt...");
var content = await client.GetStringAsync(certdataUrl); var content = await client.GetStringAsync(certdataUrl);
Console.WriteLine("Parsing MULTILINE_OCTAL to PEM..."); var pemMatches = Regex.Matches(content, @"(-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----)");
var pems = ParseMozillaCertData(content); var pems = new List<string>();
foreach (Match m in pemMatches)
{
pems.Add(m.Groups[1].Value.Trim());
}
await File.WriteAllTextAsync(outputFile, string.Join("\n\n", pems)); await File.WriteAllTextAsync(outputFile, string.Join("\n\n", pems));
Console.WriteLine($"Mozilla roots saved to: {outputFile} ({pems.Count} certificates)"); Console.WriteLine($"Mozilla roots saved to: {outputFile} ({pems.Count} certificates)");
} }
List<string> ParseMozillaCertData(string text)
{
var pems = new List<string>();
var matches = Regex.Matches(text,
@"CKA_VALUE MULTILINE_OCTAL\s*([\s\S]*?)\s*END",
RegexOptions.Multiline);
foreach (Match m in matches)
{
var octalBlock = m.Groups[1].Value.Trim();
var der = OctalToBytes(octalBlock);
if (der.Length > 0)
{
var pem = ConvertToPem(der);
pems.Add(pem);
}
}
return pems;
}
byte[] OctalToBytes(string octalBlock)
{
var bytes = new List<byte>();
var matches = Regex.Matches(octalBlock, @"\\(\d{1,3})");
foreach (Match m in matches)
{
bytes.Add((byte)Convert.ToInt32(m.Groups[1].Value, 8));
}
return bytes.ToArray();
}
string ConvertToPem(byte[] der)
{
var base64 = Convert.ToBase64String(der);
var sb = new StringBuilder();
sb.Append("-----BEGIN CERTIFICATE-----\n");
for (int i = 0; i < base64.Length; i += 64)
{
var length = Math.Min(64, base64.Length - i);
sb.Append(base64.Substring(i, length));
sb.Append("\n");
}
sb.Append("-----END CERTIFICATE-----\n");
return sb.ToString().TrimEnd();
}
async Task ProcessChromeAsync(string outputDir) async Task ProcessChromeAsync(string outputDir)
{ {
const string chromeCertsUrl = "https://chromium.googlesource.com/chromium/src/+/main/net/data/ssl/chrome_root_store/root_store.certs?format=TEXT"; const string chromeCertsUrl = "https://chromium.googlesource.com/chromium/src/+/main/net/data/ssl/chrome_root_store/root_store.certs?format=TEXT";
+1 -1
View File
@@ -52,7 +52,7 @@ jobs:
dotnet --list-sdks 2>$null; $LASTEXITCODE=0 dotnet --list-sdks 2>$null; $LASTEXITCODE=0
- name: Setup .NET 10.0.1xx - name: Setup .NET 10.0.1xx
uses: actions/setup-dotnet@v5.4.0 uses: actions/setup-dotnet@v6.0.0
with: with:
dotnet-version: 10.0.1xx dotnet-version: 10.0.1xx
+1 -1
View File
@@ -69,7 +69,7 @@ jobs:
dotnet --list-sdks 2>$null; $LASTEXITCODE=0 dotnet --list-sdks 2>$null; $LASTEXITCODE=0
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v5.4.0 uses: actions/setup-dotnet@v6.0.0
with: with:
dotnet-version: '10.0.1xx' dotnet-version: '10.0.1xx'
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
fetch-depth: '0' fetch-depth: '0'
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v5.4.0 uses: actions/setup-dotnet@v6.0.0
with: with:
dotnet-version: '8.0.x' dotnet-version: '8.0.x'
+1 -1
View File
@@ -597,7 +597,7 @@ package_binary() {
write_desktop_file "$stage" write_desktop_file "$stage"
write_maintainer_scripts "$debian_dir" write_maintainer_scripts "$debian_dir"
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.2.0), coreutils (>= 9.5), bash (>= 5.2.26), libfreetype6 (>= 2.13)" extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 9.4), bash (>= 5.2.21), libfreetype6 (>= 2.13)"
mkdir -p "$workdir/debian" mkdir -p "$workdir/debian"
cat > "$workdir/debian/control" <<EOF cat > "$workdir/debian/control" <<EOF
+2 -2
View File
@@ -12,7 +12,7 @@ MIN_KERNEL="5.10"
PKGROOT="v2rayN-publish" PKGROOT="v2rayN-publish"
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj" PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
OUTPUT_DIR="${HOME}/debbuild" OUTPUT_DIR="${HOME}/debbuild"
DOTNET_RISCV_VERSION="10.0.109" DOTNET_RISCV_VERSION="10.0.110"
DOTNET_RISCV_BASE="https://github.com/xujiegb/dotnet-riscv/releases/download" DOTNET_RISCV_BASE="https://github.com/xujiegb/dotnet-riscv/releases/download"
DOTNET_RISCV_FILE="dotnet-sdk-${DOTNET_RISCV_VERSION}-linux-riscv64.tar.gz" DOTNET_RISCV_FILE="dotnet-sdk-${DOTNET_RISCV_VERSION}-linux-riscv64.tar.gz"
DOTNET_SDK_URL="${DOTNET_RISCV_BASE}/${DOTNET_RISCV_VERSION}/${DOTNET_RISCV_FILE}" DOTNET_SDK_URL="${DOTNET_RISCV_BASE}/${DOTNET_RISCV_VERSION}/${DOTNET_RISCV_FILE}"
@@ -595,7 +595,7 @@ package_binary() {
write_desktop_file "$stage" write_desktop_file "$stage"
write_maintainer_scripts "$debian_dir" write_maintainer_scripts "$debian_dir"
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.2.0), coreutils (>= 9.5), bash (>= 5.2.26), libfreetype6 (>= 2.13)" extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 9.4), bash (>= 5.2.21), libfreetype6 (>= 2.13)"
mkdir -p "$workdir/debian" mkdir -p "$workdir/debian"
cat > "$workdir/debian/control" <<EOF cat > "$workdir/debian/control" <<EOF
+1 -1
View File
@@ -609,7 +609,7 @@ package_binary() {
write_desktop_file "$stage" write_desktop_file "$stage"
write_maintainer_scripts "$debian_dir" write_maintainer_scripts "$debian_dir"
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.2.0), coreutils (>= 9.5), bash (>= 5.2.26), libfreetype6 (>= 2.13)" extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 9.4), bash (>= 5.2.21), libfreetype6 (>= 2.13)"
mkdir -p "$workdir/debian" mkdir -p "$workdir/debian"
cat > "$workdir/debian/control" <<EOF cat > "$workdir/debian/control" <<EOF
+3 -3
View File
@@ -513,9 +513,9 @@ Requires: cairo, pango, openssl, mesa-libEGL, mesa-libGL
Requires: glibc >= 2.39 Requires: glibc >= 2.39
Requires: fontconfig >= 2.15.0 Requires: fontconfig >= 2.15.0
Requires: desktop-file-utils >= 0.26 Requires: desktop-file-utils >= 0.26
Requires: xdg-utils >= 1.2.0 Requires: xdg-utils >= 1.1.3
Requires: coreutils >= 9.5 Requires: coreutils >= 9.4
Requires: bash >= 5.2.26 Requires: bash >= 5.2.21
Requires: freetype >= 2.13 Requires: freetype >= 2.13
%description %description
+4 -4
View File
@@ -12,7 +12,7 @@ MIN_KERNEL="5.10"
PKGROOT="v2rayN-publish" PKGROOT="v2rayN-publish"
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj" PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
RPM_TOPDIR="${HOME}/rpmbuild" RPM_TOPDIR="${HOME}/rpmbuild"
DOTNET_RISCV_VERSION="10.0.109" DOTNET_RISCV_VERSION="10.0.110"
DOTNET_RISCV_BASE="https://github.com/xujiegb/dotnet-riscv/releases/download" DOTNET_RISCV_BASE="https://github.com/xujiegb/dotnet-riscv/releases/download"
DOTNET_RISCV_FILE="dotnet-sdk-${DOTNET_RISCV_VERSION}-linux-riscv64.tar.gz" DOTNET_RISCV_FILE="dotnet-sdk-${DOTNET_RISCV_VERSION}-linux-riscv64.tar.gz"
DOTNET_SDK_URL="${DOTNET_RISCV_BASE}/${DOTNET_RISCV_VERSION}/${DOTNET_RISCV_FILE}" DOTNET_SDK_URL="${DOTNET_RISCV_BASE}/${DOTNET_RISCV_VERSION}/${DOTNET_RISCV_FILE}"
@@ -512,9 +512,9 @@ Requires: cairo, pango, openssl, mesa-libEGL, mesa-libGL
Requires: glibc >= 2.39 Requires: glibc >= 2.39
Requires: fontconfig >= 2.15.0 Requires: fontconfig >= 2.15.0
Requires: desktop-file-utils >= 0.26 Requires: desktop-file-utils >= 0.26
Requires: xdg-utils >= 1.2.0 Requires: xdg-utils >= 1.1.3
Requires: coreutils >= 9.5 Requires: coreutils >= 9.4
Requires: bash >= 5.2.26 Requires: bash >= 5.2.21
Requires: freetype >= 2.13 Requires: freetype >= 2.13
%description %description
+3 -3
View File
@@ -501,9 +501,9 @@ Requires: cairo, pango, openssl, mesa-libEGL, mesa-libGL
Requires: glibc >= 2.39 Requires: glibc >= 2.39
Requires: fontconfig >= 2.15.0 Requires: fontconfig >= 2.15.0
Requires: desktop-file-utils >= 0.26 Requires: desktop-file-utils >= 0.26
Requires: xdg-utils >= 1.2.0 Requires: xdg-utils >= 1.1.3
Requires: coreutils >= 9.5 Requires: coreutils >= 9.4
Requires: bash >= 5.2.26 Requires: bash >= 5.2.21
Requires: freetype >= 2.13 Requires: freetype >= 2.13
%description %description
+1 -1
View File
@@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>7.24.0</Version> <Version>7.24.1</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
@@ -59,7 +59,7 @@ internal static class CoreConfigTestFactory
}, },
WebDavItem = new WebDavItem(), WebDavItem = new WebDavItem(),
CheckUpdateItem = new CheckUpdateItem(), CheckUpdateItem = new CheckUpdateItem(),
Fragment4RayItem = new Fragment4RayItem { Packets = "tlshello", Length = "100-200", Interval = "10-20" }, Fragment4RayItem = new Fragment4RayItem { Packets = "tlshello", Lengths = ["100-200"], Delays = ["10-20"] },
Inbound = Inbound =
[ [
new InItem new InItem
@@ -84,6 +84,7 @@ internal static class CoreConfigTestFactory
ParallelQuery = false, ParallelQuery = false,
Strategy4Freedom = Global.AsIs, Strategy4Freedom = Global.AsIs,
Strategy4Proxy = Global.AsIs, Strategy4Proxy = Global.AsIs,
Strategy4ProxyDial = Global.AsIs,
}, },
IndexId = string.Empty, IndexId = string.Empty,
SubIndexId = string.Empty, SubIndexId = string.Empty,
@@ -567,7 +567,7 @@ public class CoreConfigV2rayServiceTests
var directOutbound = cfg.outbounds.FirstOrDefault(o => o.tag == Global.DirectTag && o.protocol == "freedom"); var directOutbound = cfg.outbounds.FirstOrDefault(o => o.tag == Global.DirectTag && o.protocol == "freedom");
directOutbound.Should().NotBeNull(); directOutbound.Should().NotBeNull();
directOutbound!.settings.domainStrategy.Should().Be("UseIPv4"); directOutbound!.streamSettings.sockopt!.domainStrategy.Should().Be("UseIPv4");
} }
[Fact] [Fact]
+9 -4
View File
@@ -485,12 +485,17 @@ public class Utils
public static string? DomainStrategy4Sbox(string? strategy) public static string? DomainStrategy4Sbox(string? strategy)
{ {
if (strategy is null)
{
return null;
}
return strategy switch return strategy switch
{ {
not null when strategy.StartsWith("UseIPv4") => "prefer_ipv4", _ when strategy.StartsWith("UseIPv6") => "prefer_ipv6",
not null when strategy.StartsWith("UseIPv6") => "prefer_ipv6", _ when strategy.StartsWith("UseIP") => "prefer_ipv4",
not null when strategy.StartsWith("ForceIPv4") => "ipv4_only", _ when strategy.StartsWith("ForceIPv6") => "ipv6_only",
not null when strategy.StartsWith("ForceIPv6") => "ipv6_only", _ when strategy.StartsWith("ForceIP") => "ipv4_only",
_ => null _ => null
}; };
} }
+18 -3
View File
@@ -119,6 +119,7 @@ public static class ConfigHandler
config.SimpleDNSItem.BootstrapDNS ??= Global.DomainPureIPDNSAddress.FirstOrDefault(); config.SimpleDNSItem.BootstrapDNS ??= Global.DomainPureIPDNSAddress.FirstOrDefault();
config.SimpleDNSItem.ServeStale ??= false; config.SimpleDNSItem.ServeStale ??= false;
config.SimpleDNSItem.ParallelQuery ??= false; config.SimpleDNSItem.ParallelQuery ??= false;
config.SimpleDNSItem.EnableHappyEyeballs ??= false;
config.SpeedTestItem ??= new(); config.SpeedTestItem ??= new();
if (config.SpeedTestItem.SpeedTestTimeout < 10) if (config.SpeedTestItem.SpeedTestTimeout < 10)
@@ -168,10 +169,24 @@ public static class ConfigHandler
config.Fragment4RayItem ??= new() config.Fragment4RayItem ??= new()
{ {
Packets = "tlshello", Packets = "tlshello",
Length = "50-100",
Interval = "10-20",
MaxSplit = "0"
}; };
config.Fragment4RayItem.MaxSplit ??= "0";
config.HappyEyeballs4RayItem ??= new()
{
TryDelayMs = 250,
PrioritizeIPv6 = false,
Interleave = 1,
MaxConcurrentTry = 4,
};
if ((config.Fragment4RayItem.Lengths ?? []).Count == 0)
{
config.Fragment4RayItem.Lengths = [config.Fragment4RayItem.Length ?? "50-100"];
}
if ((config.Fragment4RayItem.Delays ?? []).Count == 0)
{
config.Fragment4RayItem.Delays = [config.Fragment4RayItem.Interval ?? "10-20"];
}
config.GlobalHotkeys ??= []; config.GlobalHotkeys ??= [];
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty()) if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
@@ -34,6 +34,7 @@ public class Config
public List<KeyEventItem> GlobalHotkeys { get; set; } public List<KeyEventItem> GlobalHotkeys { get; set; }
public List<CoreTypeItem> CoreTypeItem { get; set; } public List<CoreTypeItem> CoreTypeItem { get; set; }
public SimpleDNSItem SimpleDNSItem { get; set; } public SimpleDNSItem SimpleDNSItem { get; set; }
public HappyEyeballs4RayItem HappyEyeballs4RayItem { get; set; }
#endregion other entities #endregion other entities
} }
@@ -249,9 +249,14 @@ public class CheckUpdateItem
public class Fragment4RayItem public class Fragment4RayItem
{ {
public string? Packets { get; set; } public string? Packets { get; set; }
public List<string>? Lengths { get; set; }
public List<string>? Delays { get; set; }
public string? MaxSplit { get; set; }
// For migration from old version, remove those properties in the future
public string? Length { get; set; } public string? Length { get; set; }
public string? Interval { get; set; } public string? Interval { get; set; }
public string? MaxSplit { get; set; } // migration end
} }
[Serializable] [Serializable]
@@ -275,8 +280,19 @@ public class SimpleDNSItem
public string? BootstrapDNS { get; set; } public string? BootstrapDNS { get; set; }
public string? Strategy4Freedom { get; set; } public string? Strategy4Freedom { get; set; }
public string? Strategy4Proxy { get; set; } public string? Strategy4Proxy { get; set; }
public string? Strategy4ProxyDial { get; set; }
public bool? ServeStale { get; set; } public bool? ServeStale { get; set; }
public bool? ParallelQuery { get; set; } public bool? ParallelQuery { get; set; }
public string? Hosts { get; set; } public string? Hosts { get; set; }
public string? DirectExpectedIPs { get; set; } public string? DirectExpectedIPs { get; set; }
public bool? EnableHappyEyeballs { get; set; }
}
[Serializable]
public class HappyEyeballs4RayItem
{
public int? TryDelayMs { get; set; }
public bool? PrioritizeIPv6 { get; set; }
public int? Interleave { get; set; }
public int? MaxConcurrentTry { get; set; }
} }
@@ -136,8 +136,6 @@ public class Outboundsettings4Ray
public Response4Ray? response { get; set; } public Response4Ray? response { get; set; }
public string? domainStrategy { get; set; }
public int? userLevel { get; set; } public int? userLevel { get; set; }
public string? secretKey { get; set; } public string? secretKey { get; set; }
@@ -516,6 +514,8 @@ public class MaskSettings4Ray
public string? length { get; set; } public string? length { get; set; }
public string? delay { get; set; } public string? delay { get; set; }
public List<string>? lengths { get; set; }
public List<string>? delays { get; set; }
public int? maxSplit { get; set; } public int? maxSplit { get; set; }
// noise // noise
@@ -547,15 +547,19 @@ public class AccountsItem4Ray
public class Sockopt4Ray public class Sockopt4Ray
{ {
public string? domainStrategy { get; set; }
public string? dialerProxy { get; set; } public string? dialerProxy { get; set; }
[JsonPropertyName("interface")] [JsonPropertyName("interface")]
public string? Interface { get; set; } public string? Interface { get; set; }
public HappyEyeballs4Ray? happyEyeballs { get; set; }
} }
public class FragmentItem4Ray public class HappyEyeballs4Ray
{ {
public string? packets { get; set; } public int? tryDelayMs { get; set; }
public string? length { get; set; } public bool? prioritizeIPv6 { get; set; }
public string? interval { get; set; } public int? interleave { get; set; }
public int? maxConcurrentTry { get; set; }
} }
+36
View File
@@ -3060,6 +3060,24 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Enable Happy Eyeballs 的本地化字符串。
/// </summary>
public static string TbEnableHappyEyeballs {
get {
return ResourceManager.GetString("TbEnableHappyEyeballs", resourceCulture);
}
}
/// <summary>
/// 查找类似 Requires the UseIP Strategy. When enabled, it attempts IPv4 and IPv6 connections simultaneously and automatically selects the faster available path. 的本地化字符串。
/// </summary>
public static string TbEnableHappyEyeballsTip {
get {
return ResourceManager.GetString("TbEnableHappyEyeballsTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 DNS via Bridge 的本地化字符串。 /// 查找类似 DNS via Bridge 的本地化字符串。
/// </summary> /// </summary>
@@ -3528,6 +3546,24 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Proxy Dial Resolution Strategy 的本地化字符串。
/// </summary>
public static string TbProxyDialResolveStrategy {
get {
return ResourceManager.GetString("TbProxyDialResolveStrategy", resourceCulture);
}
}
/// <summary>
/// 查找类似 Not recommended; may cause routing loops. 的本地化字符串。
/// </summary>
public static string TbProxyDialResolveStrategyTip {
get {
return ResourceManager.GetString("TbProxyDialResolveStrategyTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Public Key 的本地化字符串。 /// 查找类似 Public Key 的本地化字符串。
/// </summary> /// </summary>
+12
View File
@@ -1830,4 +1830,16 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbRootCertificateProviderTip" xml:space="preserve"> <data name="TbRootCertificateProviderTip" xml:space="preserve">
<value>Only applies to the v2rayN GUI's downloads and network requests. Does not affect the core's certificate validation.</value> <value>Only applies to the v2rayN GUI's downloads and network requests. Does not affect the core's certificate validation.</value>
</data> </data>
<data name="TbProxyDialResolveStrategy" xml:space="preserve">
<value>Proxy Dial Resolution Strategy</value>
</data>
<data name="TbProxyDialResolveStrategyTip" xml:space="preserve">
<value>Not recommended; may cause routing loops.</value>
</data>
<data name="TbEnableHappyEyeballs" xml:space="preserve">
<value>Enable Happy Eyeballs</value>
</data>
<data name="TbEnableHappyEyeballsTip" xml:space="preserve">
<value>Requires the UseIP Strategy. When enabled, it attempts IPv4 and IPv6 connections simultaneously and automatically selects the faster available path.</value>
</data>
</root> </root>
+12
View File
@@ -1827,4 +1827,16 @@
<data name="TbRootCertificateProviderTip" xml:space="preserve"> <data name="TbRootCertificateProviderTip" xml:space="preserve">
<value>仅用于 v2rayN 界面程序的下载及网络请求,不影响核心的证书验证。</value> <value>仅用于 v2rayN 界面程序的下载及网络请求,不影响核心的证书验证。</value>
</data> </data>
<data name="TbProxyDialResolveStrategy" xml:space="preserve">
<value>连接代理解析策略</value>
</data>
<data name="TbProxyDialResolveStrategyTip" xml:space="preserve">
<value>不建议开启,特殊情况可能回环。</value>
</data>
<data name="TbEnableHappyEyeballs" xml:space="preserve">
<value>启用 Happy Eyeballs</value>
</data>
<data name="TbEnableHappyEyeballsTip" xml:space="preserve">
<value>需配合 UseIP 策略使用。启用后将同时尝试 IPv4 和 IPv6 连接,并自动选择更快可用的路径。</value>
</data>
</root> </root>
File diff suppressed because it is too large Load Diff
@@ -171,7 +171,7 @@ public partial class CoreConfigSingboxService
_coreConfig.dns.rules.Add(new() _coreConfig.dns.rules.Add(new()
{ {
server = Global.SingboxDirectDNSTag, server = Global.SingboxDirectDNSTag,
strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom), strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4ProxyDial),
domain = context.ProtectDomainList.ToList(), domain = context.ProtectDomainList.ToList(),
}); });
} }
@@ -417,11 +417,15 @@ public partial class CoreConfigSingboxService
var tls = new Tls4Sbox() var tls = new Tls4Sbox()
{ {
enabled = true, enabled = true,
record_fragment = _config.CoreBasicItem.EnableFragment ? true : null,
server_name = serverName, server_name = serverName,
insecure = _node.GetAllowInsecure(), insecure = _node.GetAllowInsecure(),
alpn = _node.GetAlpn(), alpn = _node.GetAlpn(),
}; };
if (_config.CoreBasicItem.EnableFragment == true)
{
tls.fragment = true;
tls.record_fragment = true;
}
if (_node.Fingerprint.IsNotEmpty()) if (_node.Fingerprint.IsNotEmpty())
{ {
tls.utls = new Utls4Sbox() tls.utls = new Utls4Sbox()
@@ -10,18 +10,27 @@ public partial class CoreConfigSingboxService
var simpleDnsItem = context.SimpleDnsItem; var simpleDnsItem = context.SimpleDnsItem;
var defaultDomainResolverTag = Global.SingboxDirectDNSTag; var defaultDomainResolverTag = Global.SingboxDirectDNSTag;
var directDnsStrategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom); var dialDnsStrategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4ProxyDial);
var rawDNSItem = context.RawDnsItem; var rawDNSItem = context.RawDnsItem;
if (rawDNSItem is { Enabled: true }) if (rawDNSItem is { Enabled: true })
{ {
defaultDomainResolverTag = Global.SingboxLocalDNSTag; defaultDomainResolverTag = Global.SingboxLocalDNSTag;
directDnsStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? null : rawDNSItem.DomainStrategy4Freedom; dialDnsStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? null : rawDNSItem.DomainStrategy4Freedom;
}
else if (!simpleDnsItem.Strategy4Freedom.IsNullOrEmpty())
{
var directOutbound = _coreConfig.outbounds.FirstOrDefault(o => o.tag == Global.DirectTag);
directOutbound?.domain_resolver = new()
{
server = defaultDomainResolverTag,
strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom),
};
} }
_coreConfig.route.default_domain_resolver = new() _coreConfig.route.default_domain_resolver = new()
{ {
server = defaultDomainResolverTag, server = defaultDomainResolverTag,
strategy = directDnsStrategy strategy = dialDnsStrategy
}; };
if (context.IsTunEnabled) if (context.IsTunEnabled)
@@ -43,11 +43,7 @@ public partial class CoreConfigV2rayService
var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag }); var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
if (outbound != null) if (outbound != null)
{ {
outbound.settings = new() FillSockoptDomainStrategy(outbound, strategy4Freedom);
{
domainStrategy = strategy4Freedom,
userLevel = 0
};
} }
} }
@@ -64,6 +60,22 @@ public partial class CoreConfigV2rayService
.ForEach(outbound => outbound.targetStrategy = strategy4Proxy); .ForEach(outbound => outbound.targetStrategy = strategy4Proxy);
} }
var strategy4DialProxy = simpleDnsItem?.Strategy4ProxyDial ?? Global.AsIs;
//Outbound DialProxy domainStrategy
if (strategy4DialProxy.IsNotEmpty() && strategy4DialProxy != Global.AsIs)
{
var xraySupportConfigTypeNames = Global.XraySupportConfigType
.Select(x => x == EConfigType.Hysteria2 ? "hysteria" : Global.ProtocolTypes[x])
.ToHashSet();
_coreConfig.outbounds
.Where(t => xraySupportConfigTypeNames.Contains(t.protocol))
.ToList()
.ForEach(outbound =>
{
FillSockoptDomainStrategy(outbound, strategy4DialProxy);
});
}
FillDnsServers(dnsItem); FillDnsServers(dnsItem);
FillDnsHosts(dnsItem); FillDnsHosts(dnsItem);
@@ -384,11 +396,9 @@ public partial class CoreConfigV2rayService
var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag }); var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
if (outbound != null) if (outbound != null)
{ {
outbound.settings = new() outbound.streamSettings ??= new();
{ outbound.streamSettings.sockopt ??= new();
domainStrategy = domainStrategy4Freedom, outbound.streamSettings.sockopt.domainStrategy = domainStrategy4Freedom;
userLevel = 0,
};
} }
} }
@@ -471,4 +481,28 @@ public partial class CoreConfigV2rayService
}; };
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer)); servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
} }
private void FillSockoptDomainStrategy(Outbounds4Ray outbound, string? domainStrategy, bool skipHappyEyeballs = false)
{
if (domainStrategy.IsNullOrEmpty())
{
return;
}
outbound.streamSettings ??= new();
outbound.streamSettings.sockopt ??= new();
var sockopt = outbound.streamSettings.sockopt;
sockopt.domainStrategy = domainStrategy;
if (skipHappyEyeballs || _config.SimpleDNSItem.EnableHappyEyeballs != true)
{
return;
}
var happyEyeballsItem = _config.HappyEyeballs4RayItem;
sockopt.happyEyeballs ??= new();
var happyEyeballs = sockopt.happyEyeballs;
happyEyeballs.tryDelayMs = happyEyeballsItem.TryDelayMs;
happyEyeballs.prioritizeIPv6 = happyEyeballsItem.PrioritizeIPv6;
happyEyeballs.interleave = happyEyeballsItem.Interleave;
happyEyeballs.maxConcurrentTry = happyEyeballsItem.MaxConcurrentTry;
}
} }
@@ -865,21 +865,10 @@ public partial class CoreConfigV2rayService
&& (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true)) && (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true))
.ToList(); .ToList();
var (fragmentMask, noiseMask) = BuildFragmentsMasks(); var fragmentMask = BuildFragmentsMasks();
foreach (var outbound in actOutboundWithTlsList) foreach (var outbound in actOutboundWithTlsList)
{ {
//var packets = configPackets;
//if (outbound.streamSettings.security == Global.StreamSecurityReality
// && packets == "tlshello")
//{
// packets = "1-3";
//}
//else if (outbound.streamSettings.security == Global.StreamSecurity
// && packets != "tlshello")
//{
// packets = "tlshello";
//}
var finalMaskJsonObj = JsonUtils.ParseJson(JsonUtils.Serialize(outbound.streamSettings?.finalmask)) as JsonObject ?? new JsonObject(); var finalMaskJsonObj = JsonUtils.ParseJson(JsonUtils.Serialize(outbound.streamSettings?.finalmask)) as JsonObject ?? new JsonObject();
// tcp fragment // tcp fragment
var tcpFinalmaskList = finalMaskJsonObj["tcp"] as JsonArray ?? []; var tcpFinalmaskList = finalMaskJsonObj["tcp"] as JsonArray ?? [];
@@ -888,13 +877,6 @@ public partial class CoreConfigV2rayService
tcpFinalmaskList.Add(JsonUtils.SerializeToNode(fragmentMask)); tcpFinalmaskList.Add(JsonUtils.SerializeToNode(fragmentMask));
finalMaskJsonObj["tcp"] = tcpFinalmaskList; finalMaskJsonObj["tcp"] = tcpFinalmaskList;
} }
// udp noise
var udpFinalmaskList = finalMaskJsonObj["udp"] as JsonArray ?? [];
if (udpFinalmaskList.Count == 0)
{
udpFinalmaskList.Add(JsonUtils.SerializeToNode(noiseMask));
finalMaskJsonObj["udp"] = udpFinalmaskList;
}
// write back // write back
outbound.streamSettings.finalmask = finalMaskJsonObj; outbound.streamSettings.finalmask = finalMaskJsonObj;
} }
@@ -902,7 +884,7 @@ public partial class CoreConfigV2rayService
private void ApplyFinalFragment() private void ApplyFinalFragment()
{ {
var (fragmentMask, noiseMask) = BuildFragmentsMasks(); var fragmentMask = BuildFragmentsMasks();
var actOutboundList = _coreConfig.outbounds.Where(n => n.tag.StartsWith(Global.ProxyTag)).ToList(); var actOutboundList = _coreConfig.outbounds.Where(n => n.tag.StartsWith(Global.ProxyTag)).ToList();
var fragmentFreedom = new Outbounds4Ray() var fragmentFreedom = new Outbounds4Ray()
@@ -914,9 +896,8 @@ public partial class CoreConfigV2rayService
finalmask = new Finalmask4Ray finalmask = new Finalmask4Ray
{ {
tcp = [fragmentMask], tcp = [fragmentMask],
udp = [noiseMask], },
} },
}
}; };
foreach (var outbound in actOutboundList) foreach (var outbound in actOutboundList)
@@ -934,13 +915,22 @@ public partial class CoreConfigV2rayService
} }
} }
private (Mask4Ray tcpFragment, Mask4Ray udpNoise) BuildFragmentsMasks() private Mask4Ray BuildFragmentsMasks()
{ {
var configPackets = _config.Fragment4RayItem?.Packets.NullIfEmpty() ?? "tlshello"; var configPackets = _config.Fragment4RayItem?.Packets.NullIfEmpty() ?? "tlshello";
var configLength = _config.Fragment4RayItem?.Length.NullIfEmpty() ?? "50-100"; var configLengths = _config.Fragment4RayItem?.Lengths ?? [];
var configDelay = _config.Fragment4RayItem?.Interval.NullIfEmpty() ?? "10-20"; var configDelays = _config.Fragment4RayItem?.Delays ?? [];
var configMaxSplit = _config.Fragment4RayItem?.MaxSplit.NullIfEmpty() ?? "0"; var configMaxSplit = _config.Fragment4RayItem?.MaxSplit.NullIfEmpty() ?? "0";
if (configLengths.Count == 0)
{
configLengths = ["50-100"];
}
if (configDelays.Count == 0)
{
configDelays = ["10-20"];
}
var maxSplit = 0; var maxSplit = 0;
var parts = configMaxSplit.Split('-'); var parts = configMaxSplit.Split('-');
if (parts.Length > 0 && int.TryParse(parts[0], out var ms)) if (parts.Length > 0 && int.TryParse(parts[0], out var ms))
@@ -954,21 +944,15 @@ public partial class CoreConfigV2rayService
settings = new MaskSettings4Ray settings = new MaskSettings4Ray
{ {
packets = configPackets, packets = configPackets,
length = configLength, lengths = configLengths,
delay = configDelay, delays = configDelays,
maxSplit = maxSplit, maxSplit = maxSplit,
} // For legacy xray compatibility, remove this in the future
}; length = configLengths.FirstOrDefault(),
var noiseMask = new Mask4Ray delay = configDelays.FirstOrDefault(),
{ },
type = "noise",
settings = new MaskSettings4Ray
{
length = "10-20",
delay = "10-16",
}
}; };
return (fragmentMask, noiseMask); return fragmentMask;
} }
} }
@@ -4,19 +4,21 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable
{ {
public event EventHandler? RequestClose; public event EventHandler? RequestClose;
[Reactive] public bool? UseSystemHosts { get; set; } [Reactive] public bool UseSystemHosts { get; set; }
[Reactive] public bool? AddCommonHosts { get; set; } [Reactive] public bool AddCommonHosts { get; set; }
[Reactive] public bool? FakeIP { get; set; } [Reactive] public bool FakeIP { get; set; }
[Reactive] public bool? BlockBindingQuery { get; set; } [Reactive] public bool BlockBindingQuery { get; set; }
[Reactive] public string? DirectDNS { get; set; } [Reactive] public string DirectDNS { get; set; }
[Reactive] public string? RemoteDNS { get; set; } [Reactive] public string RemoteDNS { get; set; }
[Reactive] public string? BootstrapDNS { get; set; } [Reactive] public string BootstrapDNS { get; set; }
[Reactive] public string? Strategy4Freedom { get; set; } [Reactive] public string Strategy4Freedom { get; set; }
[Reactive] public string? Strategy4Proxy { get; set; } [Reactive] public string Strategy4Proxy { get; set; }
[Reactive] public string? Hosts { get; set; } [Reactive] public string Strategy4ProxyDial { get; set; }
[Reactive] public string? DirectExpectedIPs { get; set; } [Reactive] public string Hosts { get; set; }
[Reactive] public bool? ParallelQuery { get; set; } [Reactive] public string DirectExpectedIPs { get; set; }
[Reactive] public bool? ServeStale { get; set; } [Reactive] public bool ParallelQuery { get; set; }
[Reactive] public bool ServeStale { get; set; }
[Reactive] public bool EnableHappyEyeballs { get; set; }
[Reactive] public bool UseSystemHostsCompatible { get; set; } [Reactive] public bool UseSystemHostsCompatible { get; set; }
[Reactive] public string DomainStrategy4FreedomCompatible { get; set; } = string.Empty; [Reactive] public string DomainStrategy4FreedomCompatible { get; set; } = string.Empty;
@@ -67,20 +69,21 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable
{ {
_config = AppManager.Instance.Config; _config = AppManager.Instance.Config;
var item = _config.SimpleDNSItem; var item = _config.SimpleDNSItem;
UseSystemHosts = item.UseSystemHosts; UseSystemHosts = item.UseSystemHosts ?? false;
AddCommonHosts = item.AddCommonHosts; AddCommonHosts = item.AddCommonHosts ?? false;
FakeIP = item.FakeIP; FakeIP = item.FakeIP ?? false;
BlockBindingQuery = item.BlockBindingQuery; BlockBindingQuery = item.BlockBindingQuery ?? false;
DirectDNS = item.DirectDNS; DirectDNS = item.DirectDNS ?? string.Empty;
RemoteDNS = item.RemoteDNS; RemoteDNS = item.RemoteDNS ?? string.Empty;
BootstrapDNS = item.BootstrapDNS; BootstrapDNS = item.BootstrapDNS ?? string.Empty;
Strategy4Freedom = item.Strategy4Freedom; Strategy4Freedom = item.Strategy4Freedom ?? string.Empty;
Strategy4Proxy = item.Strategy4Proxy; Strategy4Proxy = item.Strategy4Proxy ?? string.Empty;
Hosts = item.Hosts; Strategy4ProxyDial = item.Strategy4ProxyDial ?? string.Empty;
DirectExpectedIPs = item.DirectExpectedIPs; Hosts = item.Hosts ?? string.Empty;
ParallelQuery = item.ParallelQuery; DirectExpectedIPs = item.DirectExpectedIPs ?? string.Empty;
ServeStale = item.ServeStale; ParallelQuery = item.ParallelQuery ?? false;
ServeStale = item.ServeStale ?? false;
EnableHappyEyeballs = item.EnableHappyEyeballs ?? false;
var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray); var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray);
RayCustomDNSEnableCompatible = item1.Enabled; RayCustomDNSEnableCompatible = item1.Enabled;
UseSystemHostsCompatible = item1.UseSystemHosts; UseSystemHostsCompatible = item1.UseSystemHosts;
@@ -108,11 +111,12 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable
_config.SimpleDNSItem.BootstrapDNS = BootstrapDNS; _config.SimpleDNSItem.BootstrapDNS = BootstrapDNS;
_config.SimpleDNSItem.Strategy4Freedom = Strategy4Freedom; _config.SimpleDNSItem.Strategy4Freedom = Strategy4Freedom;
_config.SimpleDNSItem.Strategy4Proxy = Strategy4Proxy; _config.SimpleDNSItem.Strategy4Proxy = Strategy4Proxy;
_config.SimpleDNSItem.Strategy4ProxyDial = Strategy4ProxyDial;
_config.SimpleDNSItem.Hosts = Hosts; _config.SimpleDNSItem.Hosts = Hosts;
_config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs; _config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs;
_config.SimpleDNSItem.ParallelQuery = ParallelQuery; _config.SimpleDNSItem.ParallelQuery = ParallelQuery;
_config.SimpleDNSItem.ServeStale = ServeStale; _config.SimpleDNSItem.ServeStale = ServeStale;
_config.SimpleDNSItem.EnableHappyEyeballs = EnableHappyEyeballs;
if (NormalDNSCompatible.IsNotEmpty()) if (NormalDNSCompatible.IsNotEmpty())
{ {
var obj = JsonUtils.ParseJson(NormalDNSCompatible); var obj = JsonUtils.ParseJson(NormalDNSCompatible);
@@ -29,24 +29,12 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
[Reactive] public bool EnableFragment { get; set; } [Reactive] public bool EnableFragment { get; set; }
[Reactive] public bool EnableFinalFragment { get; set; } [Reactive] public bool EnableFinalFragment { get; set; }
[Reactive] public string FragmentPackets { get; set; } [Reactive] public string FragmentPackets { get; set; }
[Reactive] public string FragmentLength { get; set; } [Reactive] public string FragmentLengths { get; set; }
[Reactive] public string FragmentInterval { get; set; } [Reactive] public string FragmentDelays { get; set; }
[Reactive] public string FragmentMaxSplit { get; set; } [Reactive] public string FragmentMaxSplit { get; set; }
#endregion Core #endregion Core
#region Core KCP
//[Reactive] public int Kcpmtu { get; set; }
//[Reactive] public int Kcptti { get; set; }
//[Reactive] public int KcpuplinkCapacity { get; set; }
//[Reactive] public int KcpdownlinkCapacity { get; set; }
//[Reactive] public int KcpreadBufferSize { get; set; }
//[Reactive] public int KcpwriteBufferSize { get; set; }
//[Reactive] public bool Kcpcongestion { get; set; }
#endregion Core KCP
#region UI #region UI
[Reactive] public bool AutoRun { get; set; } [Reactive] public bool AutoRun { get; set; }
@@ -150,6 +138,7 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
SecondLocalPortEnabled = inbound.SecondLocalPortEnabled; SecondLocalPortEnabled = inbound.SecondLocalPortEnabled;
UdpEnabled = inbound.UdpEnabled; UdpEnabled = inbound.UdpEnabled;
SniffingEnabled = inbound.SniffingEnabled; SniffingEnabled = inbound.SniffingEnabled;
DestOverride = inbound.DestOverride ?? [];
RouteOnly = inbound.RouteOnly; RouteOnly = inbound.RouteOnly;
AllowLANConn = inbound.AllowLANConn; AllowLANConn = inbound.AllowLANConn;
NewPort4LAN = inbound.NewPort4LAN; NewPort4LAN = inbound.NewPort4LAN;
@@ -168,24 +157,12 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
EnableFragment = _config.CoreBasicItem.EnableFragment; EnableFragment = _config.CoreBasicItem.EnableFragment;
EnableFinalFragment = _config.CoreBasicItem.EnableFinalFragment; EnableFinalFragment = _config.CoreBasicItem.EnableFinalFragment;
FragmentPackets = _config.Fragment4RayItem?.Packets; FragmentPackets = _config.Fragment4RayItem?.Packets;
FragmentLength = _config.Fragment4RayItem?.Length; FragmentLengths = Utils.List2String(_config.Fragment4RayItem?.Lengths);
FragmentInterval = _config.Fragment4RayItem?.Interval; FragmentDelays = Utils.List2String(_config.Fragment4RayItem?.Delays);
FragmentMaxSplit = _config.Fragment4RayItem?.MaxSplit; FragmentMaxSplit = _config.Fragment4RayItem?.MaxSplit;
#endregion Core #endregion Core
#region Core KCP
//Kcpmtu = _config.kcpItem.mtu;
//Kcptti = _config.kcpItem.tti;
//KcpuplinkCapacity = _config.kcpItem.uplinkCapacity;
//KcpdownlinkCapacity = _config.kcpItem.downlinkCapacity;
//KcpreadBufferSize = _config.kcpItem.readBufferSize;
//KcpwriteBufferSize = _config.kcpItem.writeBufferSize;
//Kcpcongestion = _config.kcpItem.congestion;
#endregion Core KCP
#region UI #region UI
AutoRun = _config.GuiItem.AutoRun; AutoRun = _config.GuiItem.AutoRun;
@@ -309,34 +286,33 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
NoticeManager.Instance.Enqueue(ResUI.FillLocalListeningPort); NoticeManager.Instance.Enqueue(ResUI.FillLocalListeningPort);
return; return;
} }
var fragmentLengths = Utils.String2List(FragmentLengths) ?? [];
var fragmentDelays = Utils.String2List(FragmentDelays) ?? [];
if (fragmentLengths.Any(item => !Utils.TryParseRange(item, 0, int.MaxValue, out _, out _))
|| fragmentDelays.Any(item => !Utils.TryParseRange(item, 0, int.MaxValue, out _, out _))
|| (FragmentMaxSplit.IsNotEmpty() && !Utils.TryParseMaxSplit(FragmentMaxSplit, 0, 10000, out _, out _)))
{
NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError);
return;
}
var needReboot = EnableStatistics != _config.GuiItem.EnableStatistics var needReboot = EnableStatistics != _config.GuiItem.EnableStatistics
|| DisplayRealTimeSpeed != _config.GuiItem.DisplayRealTimeSpeed || DisplayRealTimeSpeed != _config.GuiItem.DisplayRealTimeSpeed
|| EnableDragDropSort != _config.UiItem.EnableDragDropSort || EnableDragDropSort != _config.UiItem.EnableDragDropSort
|| EnableHWA != _config.GuiItem.EnableHWA || EnableHWA != _config.GuiItem.EnableHWA
|| CurrentFontFamily != _config.UiItem.CurrentFontFamily; || CurrentFontFamily != _config.UiItem.CurrentFontFamily;
//if (Utile.IsNullOrEmpty(Kcpmtu.ToString()) || !Utile.IsNumeric(Kcpmtu.ToString())
// || Utile.IsNullOrEmpty(Kcptti.ToString()) || !Utile.IsNumeric(Kcptti.ToString())
// || Utile.IsNullOrEmpty(KcpuplinkCapacity.ToString()) || !Utile.IsNumeric(KcpuplinkCapacity.ToString())
// || Utile.IsNullOrEmpty(KcpdownlinkCapacity.ToString()) || !Utile.IsNumeric(KcpdownlinkCapacity.ToString())
// || Utile.IsNullOrEmpty(KcpreadBufferSize.ToString()) || !Utile.IsNumeric(KcpreadBufferSize.ToString())
// || Utile.IsNullOrEmpty(KcpwriteBufferSize.ToString()) || !Utile.IsNumeric(KcpwriteBufferSize.ToString()))
//{
// NoticeHandler.Instance.Enqueue(ResUI.FillKcpParameters);
// return;
//}
//Core //Core
_config.Inbound.First().LocalPort = LocalPort; var inbound = _config.Inbound.First();
_config.Inbound.First().SecondLocalPortEnabled = SecondLocalPortEnabled; inbound.LocalPort = LocalPort;
_config.Inbound.First().UdpEnabled = UdpEnabled; inbound.SecondLocalPortEnabled = SecondLocalPortEnabled;
_config.Inbound.First().SniffingEnabled = SniffingEnabled; inbound.UdpEnabled = UdpEnabled;
_config.Inbound.First().DestOverride = DestOverride?.ToList(); inbound.SniffingEnabled = SniffingEnabled;
_config.Inbound.First().RouteOnly = RouteOnly; inbound.DestOverride = DestOverride?.ToList();
_config.Inbound.First().AllowLANConn = AllowLANConn; inbound.RouteOnly = RouteOnly;
_config.Inbound.First().NewPort4LAN = NewPort4LAN; inbound.AllowLANConn = AllowLANConn;
_config.Inbound.First().User = User; inbound.NewPort4LAN = NewPort4LAN;
_config.Inbound.First().Pass = Pass; inbound.User = User;
inbound.Pass = Pass;
if (_config.Inbound.Count > 1) if (_config.Inbound.Count > 1)
{ {
_config.Inbound.RemoveAt(1); _config.Inbound.RemoveAt(1);
@@ -351,30 +327,12 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
_config.CoreBasicItem.EnableCacheFile4Sbox = EnableCacheFile4Sbox; _config.CoreBasicItem.EnableCacheFile4Sbox = EnableCacheFile4Sbox;
_config.HysteriaItem.UpMbps = HyUpMbps ?? 0; _config.HysteriaItem.UpMbps = HyUpMbps ?? 0;
_config.HysteriaItem.DownMbps = HyDownMbps ?? 0; _config.HysteriaItem.DownMbps = HyDownMbps ?? 0;
if (EnableFragment)
{
if (!Utils.TryParseRange(FragmentLength, 0, int.MaxValue, out _, out _))
{
NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError);
return;
}
if (!Utils.TryParseRange(FragmentInterval, 1, 100, out _, out _))
{
NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError);
return;
}
if (FragmentMaxSplit.IsNotEmpty()
&& !Utils.TryParseMaxSplit(FragmentMaxSplit, 0, 10000, out _, out _))
{
NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError);
return;
}
}
_config.CoreBasicItem.EnableFragment = EnableFragment; _config.CoreBasicItem.EnableFragment = EnableFragment;
_config.CoreBasicItem.EnableFinalFragment = EnableFinalFragment; _config.CoreBasicItem.EnableFinalFragment = EnableFinalFragment;
_config.Fragment4RayItem ??= new();
_config.Fragment4RayItem.Packets = FragmentPackets; _config.Fragment4RayItem.Packets = FragmentPackets;
_config.Fragment4RayItem.Length = FragmentLength; _config.Fragment4RayItem.Lengths = fragmentLengths;
_config.Fragment4RayItem.Interval = FragmentInterval; _config.Fragment4RayItem.Delays = fragmentDelays;
_config.Fragment4RayItem.MaxSplit = FragmentMaxSplit; _config.Fragment4RayItem.MaxSplit = FragmentMaxSplit;
_config.GuiItem.AutoRun = AutoRun; _config.GuiItem.AutoRun = AutoRun;
@@ -42,7 +42,7 @@
x:Name="gridBasicDNSSettings" x:Name="gridBasicDNSSettings"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
ColumnDefinitions="Auto,Auto,*" ColumnDefinitions="Auto,Auto,*"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<TextBlock <TextBlock
x:Name="txtBasicDNSSettingsInvalid" x:Name="txtBasicDNSSettingsInvalid"
@@ -167,28 +167,71 @@
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbParallelQuery}" /> Text="{x:Static resx:ResUI.TbProxyDialResolveStrategy}" />
<ToggleSwitch <ComboBox
x:Name="togParallelQuery" x:Name="cmbProxyDialDNSStrategy"
Grid.Row="7" Grid.Row="7"
Grid.Column="1" Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" VerticalAlignment="Center"
VerticalAlignment="Center" /> PlaceholderText="Default" />
<TextBlock
Grid.Row="7"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbProxyDialResolveStrategyTip}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="8" Grid.Row="8"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbServeStale}" /> Text="{x:Static resx:ResUI.TbParallelQuery}" />
<ToggleSwitch <ToggleSwitch
x:Name="togServeStale" x:Name="togParallelQuery"
Grid.Row="8" Grid.Row="8"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" /> VerticalAlignment="Center" />
<TextBlock
Grid.Row="9"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbServeStale}" />
<ToggleSwitch
x:Name="togServeStale"
Grid.Row="9"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center" />
<TextBlock
Grid.Row="10"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbEnableHappyEyeballs}" />
<ToggleSwitch
x:Name="togEnableHappyEyeballs"
Grid.Row="10"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center" />
<TextBlock
Grid.Row="10"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbEnableHappyEyeballsTip}"
TextWrapping="Wrap" />
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</TabItem> </TabItem>
@@ -318,8 +361,8 @@
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
BorderThickness="1" BorderThickness="1"
Classes="TextArea" Classes="TextArea"
TextWrapping="Wrap" PlaceholderText="{x:Static resx:ResUI.TbDNSHostsConfig}"
PlaceholderText="{x:Static resx:ResUI.TbDNSHostsConfig}" /> TextWrapping="Wrap" />
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</TabItem> </TabItem>
@@ -16,6 +16,7 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy; cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy;
cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy; cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy;
cmbProxyDialDNSStrategy.ItemsSource = Global.DomainStrategy;
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress; cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress; cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress; cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
@@ -37,10 +38,12 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4ProxyDial, v => v.cmbProxyDialDNSStrategy.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableHappyEyeballs, v => v.togEnableHappyEyeballs.IsChecked).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
@@ -347,7 +347,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsFragmentLength}" /> Text="{x:Static resx:ResUI.TbSettingsFragmentLength}" />
<TextBox <TextBox
x:Name="txtFragmentLength" x:Name="txtFragmentLengths"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="120" Width="120"
@@ -369,7 +369,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsFragmentInterval}" /> Text="{x:Static resx:ResUI.TbSettingsFragmentInterval}" />
<TextBox <TextBox
x:Name="txtFragmentInterval" x:Name="txtFragmentDelays"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="120" Width="120"
@@ -86,8 +86,8 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FragmentLength, v => v.txtFragmentLength.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FragmentLengths, v => v.txtFragmentLengths.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FragmentInterval, v => v.txtFragmentInterval.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FragmentDelays, v => v.txtFragmentDelays.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
+54 -6
View File
@@ -52,6 +52,8 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@@ -195,13 +197,23 @@
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbParallelQuery}" /> Text="{x:Static resx:ResUI.TbProxyDialResolveStrategy}" />
<ToggleButton <ComboBox
x:Name="togParallelQuery" x:Name="cmbProxyDialDNSStrategy"
Grid.Row="7" Grid.Row="7"
Grid.Column="1" Grid.Column="1"
Width="200"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" /> materialDesign:HintAssist.Hint="Default"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="7"
Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbProxyDialResolveStrategyTip}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="8" Grid.Row="8"
@@ -209,13 +221,49 @@
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbServeStale}" /> Text="{x:Static resx:ResUI.TbParallelQuery}" />
<ToggleButton <ToggleButton
x:Name="togServeStale" x:Name="togParallelQuery"
Grid.Row="8" Grid.Row="8"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock
Grid.Row="9"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbServeStale}" />
<ToggleButton
x:Name="togServeStale"
Grid.Row="9"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="10"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbEnableHappyEyeballs}" />
<ToggleButton
x:Name="togEnableHappyEyeballs"
Grid.Row="10"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="10"
Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbEnableHappyEyeballsTip}"
TextWrapping="Wrap" />
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</TabItem> </TabItem>
@@ -12,6 +12,7 @@ public partial class DNSSettingWindow
cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy; cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy;
cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy; cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy;
cmbProxyDialDNSStrategy.ItemsSource = Global.DomainStrategy;
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress; cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress; cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress; cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
@@ -33,10 +34,12 @@ public partial class DNSSettingWindow
this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4ProxyDial, v => v.cmbProxyDialDNSStrategy.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableHappyEyeballs, v => v.togEnableHappyEyeballs.IsChecked).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
+2 -2
View File
@@ -419,7 +419,7 @@
Text="{x:Static resx:ResUI.TbSettingsFragmentLength}" Text="{x:Static resx:ResUI.TbSettingsFragmentLength}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBox <TextBox
x:Name="txtFragmentLength" x:Name="txtFragmentLengths"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
@@ -437,7 +437,7 @@
Text="{x:Static resx:ResUI.TbSettingsFragmentInterval}" Text="{x:Static resx:ResUI.TbSettingsFragmentInterval}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBox <TextBox
x:Name="txtFragmentInterval" x:Name="txtFragmentDelays"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
@@ -82,8 +82,8 @@ public partial class OptionSettingWindow
this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FragmentLength, v => v.txtFragmentLength.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FragmentLengths, v => v.txtFragmentLengths.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FragmentInterval, v => v.txtFragmentInterval.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FragmentDelays, v => v.txtFragmentDelays.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.Kcpmtu, v => v.txtKcpmtu.Text).DisposeWith(disposables); //this.Bind(ViewModel, vm => vm.Kcpmtu, v => v.txtKcpmtu.Text).DisposeWith(disposables);