Compare commits

..

6 commits

Author SHA1 Message Date
DHR60
ee946e80fe
Merge 4da5dc4c96 into 49f65579aa 2026-04-11 19:47:17 +08:00
DHR60
4da5dc4c96 Tidy Resx 2026-04-07 18:28:02 +08:00
DHR60
ef31cc65b6 Fix
Fix raw http ui

Fill xhttp default mode

Fix share uri

Remove RawHost

Fix singbox tcp http path

Fix vmess share uri
2026-04-07 18:25:32 +08:00
DHR60
0ecf1f823e Fix 2026-04-07 18:25:32 +08:00
DHR60
09bada3753 Rename tcp to raw 2026-04-07 18:25:32 +08:00
DHR60
6692390c23 Refactor transport 2026-04-07 18:25:32 +08:00
27 changed files with 2 additions and 482 deletions

View file

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<Version>7.20.3</Version>
<Version>7.20.2</Version>
</PropertyGroup>
<PropertyGroup>

View file

@ -12,7 +12,6 @@
<PackageVersion Include="ReactiveUI.Avalonia" Version="11.4.12" />
<PackageVersion Include="CliWrap" Version="3.10.1" />
<PackageVersion Include="Downloader" Version="5.1.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.4.1" />
<PackageVersion Include="MaterialDesignThemes" Version="5.3.1" />
<PackageVersion Include="MessageBox.Avalonia" Version="3.3.1.1" />
@ -27,8 +26,6 @@
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="TaskScheduler" Version="2.12.2" />
<PackageVersion Include="WebDav.Client" Version="2.9.0" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
</ItemGroup>

View file

@ -1,228 +0,0 @@
using System.Text.Json.Nodes;
using ServiceLib;
using ServiceLib.Enums;
using ServiceLib.Models;
using ServiceLib.Services.CoreConfig;
using Xunit;
namespace ServiceLib.Tests;
public class CoreConfigV2rayServiceTests
{
private const string SendThrough = "198.51.100.10";
[Fact]
public void GenerateClientConfigContent_OnlyAppliesSendThroughToRemoteProxyOutbounds()
{
var node = CreateProxyNode("proxy-1", "198.51.100.1", 443);
var service = new CoreConfigV2rayService(CreateContext(node));
var result = service.GenerateClientConfigContent();
Assert.True(result.Success);
var outbounds = GetOutbounds(result.Data?.ToString());
var proxyOutbound = outbounds.Single(outbound => outbound["tag"]!.GetValue<string>() == Global.ProxyTag);
var directOutbound = outbounds.Single(outbound => outbound["tag"]!.GetValue<string>() == Global.DirectTag);
var blockOutbound = outbounds.Single(outbound => outbound["tag"]!.GetValue<string>() == Global.BlockTag);
Assert.Equal(SendThrough, proxyOutbound["sendThrough"]?.GetValue<string>());
Assert.Null(directOutbound["sendThrough"]);
Assert.Null(blockOutbound["sendThrough"]);
}
[Fact]
public void GenerateClientConfigContent_OnlyAppliesSendThroughToChainExitOutbounds()
{
var exitNode = CreateProxyNode("exit", "198.51.100.2", 443);
var entryNode = CreateProxyNode("entry", "198.51.100.3", 443);
var chainNode = CreateChainNode("chain", exitNode, entryNode);
var service = new CoreConfigV2rayService(CreateContext(
chainNode,
allProxiesMap: new Dictionary<string, ProfileItem>
{
[exitNode.IndexId] = exitNode,
[entryNode.IndexId] = entryNode,
}));
var result = service.GenerateClientConfigContent();
Assert.True(result.Success);
var outbounds = GetOutbounds(result.Data?.ToString())
.Where(outbound => outbound["protocol"]?.GetValue<string>() is not ("freedom" or "blackhole" or "dns"))
.ToList();
var sendThroughOutbounds = outbounds
.Where(outbound => outbound["sendThrough"]?.GetValue<string>() == SendThrough)
.ToList();
var chainedOutbounds = outbounds
.Where(outbound => outbound["streamSettings"]?["sockopt"]?["dialerProxy"] is not null)
.ToList();
Assert.Single(sendThroughOutbounds);
Assert.All(chainedOutbounds, outbound => Assert.Null(outbound["sendThrough"]));
}
[Fact]
public void GenerateClientConfigContent_DoesNotApplySendThroughToTunRelayLoopbackOutbound()
{
var node = CreateProxyNode("proxy-1", "198.51.100.4", 443);
var config = CreateConfig();
config.TunModeItem.EnableLegacyProtect = false;
var service = new CoreConfigV2rayService(CreateContext(
node,
config,
isTunEnabled: true,
tunProtectSsPort: 10811,
proxyRelaySsPort: 10812));
var result = service.GenerateClientConfigContent();
Assert.True(result.Success);
var outbounds = GetOutbounds(result.Data?.ToString());
Assert.DoesNotContain(outbounds, outbound => outbound["sendThrough"]?.GetValue<string>() == SendThrough);
}
private static CoreConfigContext CreateContext(
ProfileItem node,
Config? config = null,
Dictionary<string, ProfileItem>? allProxiesMap = null,
bool isTunEnabled = false,
int tunProtectSsPort = 0,
int proxyRelaySsPort = 0)
{
return new CoreConfigContext
{
Node = node,
RunCoreType = ECoreType.Xray,
AppConfig = config ?? CreateConfig(),
AllProxiesMap = allProxiesMap ?? new(),
SimpleDnsItem = new SimpleDNSItem(),
IsTunEnabled = isTunEnabled,
TunProtectSocksPort = tunProtectSsPort,
ProxyRelaySocksPort = proxyRelaySsPort,
};
}
private static Config CreateConfig()
{
return new Config
{
IndexId = string.Empty,
SubIndexId = string.Empty,
CoreBasicItem = new()
{
LogEnabled = false,
Loglevel = "warning",
MuxEnabled = false,
DefAllowInsecure = false,
DefFingerprint = Global.Fingerprints.First(),
DefUserAgent = string.Empty,
SendThrough = SendThrough,
EnableFragment = false,
EnableCacheFile4Sbox = true,
},
TunModeItem = new()
{
EnableTun = false,
AutoRoute = true,
StrictRoute = true,
Stack = string.Empty,
Mtu = 9000,
EnableIPv6Address = false,
IcmpRouting = Global.TunIcmpRoutingPolicies.First(),
EnableLegacyProtect = false,
},
KcpItem = new(),
GrpcItem = new(),
RoutingBasicItem = new()
{
DomainStrategy = Global.DomainStrategies.First(),
DomainStrategy4Singbox = Global.DomainStrategies4Sbox.First(),
RoutingIndexId = string.Empty,
},
GuiItem = new(),
MsgUIItem = new(),
UiItem = new()
{
CurrentLanguage = "en",
CurrentFontFamily = string.Empty,
MainColumnItem = [],
WindowSizeItem = [],
},
ConstItem = new(),
SpeedTestItem = new(),
Mux4RayItem = new()
{
Concurrency = 8,
XudpConcurrency = 8,
XudpProxyUDP443 = "reject",
},
Mux4SboxItem = new()
{
Protocol = string.Empty,
},
HysteriaItem = new(),
ClashUIItem = new()
{
ConnectionsColumnItem = [],
},
SystemProxyItem = new(),
WebDavItem = new(),
CheckUpdateItem = new(),
Fragment4RayItem = null,
Inbound = [new InItem
{
Protocol = EInboundProtocol.socks.ToString(),
LocalPort = 10808,
UdpEnabled = true,
SniffingEnabled = true,
RouteOnly = false,
}],
GlobalHotkeys = [],
CoreTypeItem = [],
SimpleDNSItem = new(),
};
}
private static ProfileItem CreateProxyNode(string indexId, string address, int port)
{
return new ProfileItem
{
IndexId = indexId,
Remarks = indexId,
ConfigType = EConfigType.SOCKS,
CoreType = ECoreType.Xray,
Address = address,
Port = port,
};
}
private static ProfileItem CreateChainNode(string indexId, params ProfileItem[] nodes)
{
var chainNode = new ProfileItem
{
IndexId = indexId,
Remarks = indexId,
ConfigType = EConfigType.ProxyChain,
CoreType = ECoreType.Xray,
};
chainNode.SetProtocolExtra(new ProtocolExtraItem
{
ChildItems = string.Join(',', nodes.Select(node => node.IndexId)),
});
return chainNode;
}
private static List<JsonObject> GetOutbounds(string? json)
{
var root = JsonNode.Parse(json ?? throw new InvalidOperationException("Config JSON is missing"))?.AsObject()
?? throw new InvalidOperationException("Failed to parse config JSON");
return root["outbounds"]?.AsArray().Select(node => node!.AsObject()).ToList()
?? throw new InvalidOperationException("Config JSON does not contain outbounds");
}
}

View file

@ -1,21 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ServiceLib\ServiceLib.csproj" />
</ItemGroup>
</Project>

View file

@ -522,23 +522,6 @@ public class Utils
return false;
}
public static bool IsIpv4(string? ip)
{
if (ip.IsNullOrEmpty())
{
return false;
}
ip = ip.Trim();
if (!IPAddress.TryParse(ip, out var address))
{
return false;
}
return address.AddressFamily == AddressFamily.InterNetwork
&& ip.Count(c => c == '.') == 3;
}
public static bool IsIpAddress(string? ip)
{
if (ip.IsNullOrEmpty())

View file

@ -41,7 +41,6 @@ public static class ConfigHandler
Loglevel = "warning",
MuxEnabled = false,
};
config.CoreBasicItem.SendThrough = config.CoreBasicItem.SendThrough?.TrimEx();
if (config.Inbound == null)
{

View file

@ -15,8 +15,6 @@ public class CoreBasicItem
public string DefUserAgent { get; set; }
public string? SendThrough { get; set; }
public bool EnableFragment { get; set; }
public bool EnableCacheFile4Sbox { get; set; } = true;

View file

@ -105,8 +105,6 @@ public class Outbounds4Ray
public string protocol { get; set; }
public string? sendThrough { get; set; }
public string? targetStrategy { get; set; }
public Outboundsettings4Ray settings { get; set; }

View file

@ -222,15 +222,6 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Please fill in the correct IPv4 address for SendThrough. 的本地化字符串。
/// </summary>
public static string FillCorrectSendThroughIPv4 {
get {
return ResourceManager.GetString("FillCorrectSendThroughIPv4", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please enter the correct port format. 的本地化字符串。
/// </summary>
@ -4167,24 +4158,6 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Local outbound address (SendThrough) 的本地化字符串。
/// </summary>
public static string TbSettingsSendThrough {
get {
return ResourceManager.GetString("TbSettingsSendThrough", resourceCulture);
}
}
/// <summary>
/// 查找类似 For multi-interface environments, enter the local machine&apos;s IPv4 address 的本地化字符串。
/// </summary>
public static string TbSettingsSendThroughTip {
get {
return ResourceManager.GetString("TbSettingsSendThroughTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Set Win10 UWP Loopback 的本地化字符串。
/// </summary>

View file

@ -1695,9 +1695,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbLegacyProtect" xml:space="preserve">
<value>Legacy TUN Protect</value>
</data>
<data name="TbSettingsSendThroughTip" xml:space="preserve">
<value>For multi-interface environments, enter the local machine's IPv4 address</value>
</data>
<data name="TbCamouflageDomain" xml:space="preserve">
<value>Camouflage domain</value>
</data>

View file

@ -1692,9 +1692,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbLegacyProtect" xml:space="preserve">
<value>Legacy TUN Protect</value>
</data>
<data name="TbSettingsSendThroughTip" xml:space="preserve">
<value>For multi-interface environments, enter the local machine's IPv4 address</value>
</data>
<data name="TbCamouflageDomain" xml:space="preserve">
<value>Domaine de camouflage</value>
</data>

View file

@ -1695,9 +1695,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbLegacyProtect" xml:space="preserve">
<value>Legacy TUN Protect</value>
</data>
<data name="TbSettingsSendThroughTip" xml:space="preserve">
<value>For multi-interface environments, enter the local machine's IPv4 address</value>
</data>
<data name="TbCamouflageDomain" xml:space="preserve">
<value>Álcázási tartomány</value>
</data>

View file

@ -1317,15 +1317,6 @@
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
</data>
<data name="TbSettingsSendThrough" xml:space="preserve">
<value>Local outbound address (SendThrough)</value>
</data>
<data name="TbSettingsSendThroughTip" xml:space="preserve">
<value>For multi-interface environments, enter the local machine's IPv4 address</value>
</data>
<data name="FillCorrectSendThroughIPv4" xml:space="preserve">
<value>Please fill in the correct IPv4 address for SendThrough.</value>
</data>
<data name="TransportHeaderType5" xml:space="preserve">
<value>xhttp mode</value>
</data>

View file

@ -1695,13 +1695,10 @@
<data name="TbLegacyProtect" xml:space="preserve">
<value>Устаревшая защита TUN (Legacy Protect)</value>
</data>
<data name="TbSettingsSendThroughTip" xml:space="preserve">
<value>For multi-interface environments, enter the local machine's IPv4 address</value>
</data>
<data name="TbCamouflageDomain" xml:space="preserve">
<value>Камуфляжный домен</value>
</data>
<data name="TbHost" xml:space="preserve">
<value>Host</value>
</data>
</root>
</root>

View file

@ -1314,15 +1314,6 @@
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密码将调用命令行校验,如果因为校验错误导致无法正常运行时,请重启本应用。 密码不会存储,每次重启后都需要再次输入。</value>
</data>
<data name="TbSettingsSendThrough" xml:space="preserve">
<value>本地出站地址 (SendThrough)</value>
</data>
<data name="TbSettingsSendThroughTip" xml:space="preserve">
<value>用于多网口环境,请填写本机 IPv4 地址</value>
</data>
<data name="FillCorrectSendThroughIPv4" xml:space="preserve">
<value>请填写正确的 SendThrough IPv4 地址。</value>
</data>
<data name="TransportHeaderType5" xml:space="preserve">
<value>XHTTP 模式</value>
</data>

View file

@ -1692,9 +1692,6 @@
<data name="TbLegacyProtect" xml:space="preserve">
<value>Legacy TUN Protect</value>
</data>
<data name="TbSettingsSendThroughTip" xml:space="preserve">
<value>For multi-interface environments, enter the local machine's IPv4 address</value>
</data>
<data name="TbCamouflageDomain" xml:space="preserve">
<value>偽裝域名</value>
</data>

View file

@ -57,8 +57,6 @@ public partial class CoreConfigSingboxService(CoreConfigContext context)
ConvertGeo2Ruleset();
ApplyOutboundSendThrough();
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
@ -223,7 +221,6 @@ public partial class CoreConfigSingboxService(CoreConfigContext context)
_coreConfig.route.rules.Add(rule);
}
ApplyOutboundSendThrough();
ret.Success = true;
ret.Data = JsonUtils.Serialize(_coreConfig);
return ret;
@ -282,7 +279,6 @@ public partial class CoreConfigSingboxService(CoreConfigContext context)
listen_port = port,
type = EInboundProtocol.mixed.ToString(),
});
ApplyOutboundSendThrough();
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;

View file

@ -58,40 +58,4 @@ public partial class CoreConfigSingboxService
return JsonUtils.Serialize(fullConfigTemplateNode);
}
private void ApplyOutboundSendThrough()
{
var sendThrough = _config.CoreBasicItem.SendThrough?.TrimEx();
foreach (var outbound in _coreConfig.outbounds ?? [])
{
outbound.inet4_bind_address = ShouldApplySendThrough(outbound, sendThrough) ? sendThrough : null;
}
}
private static bool ShouldApplySendThrough(Outbound4Sbox outbound, string? sendThrough)
{
if (sendThrough.IsNullOrEmpty())
{
return false;
}
if (outbound.type is "direct" or "block" or "dns" or "selector" or "urltest")
{
return false;
}
if (!outbound.detour.IsNullOrEmpty())
{
return false;
}
var outboundAddress = outbound.server ?? string.Empty;
if (outboundAddress.Equals("localhost", StringComparison.OrdinalIgnoreCase))
{
return false;
}
return !IPAddress.TryParse(outboundAddress, out var address) || !IPAddress.IsLoopback(address);
}
}

View file

@ -62,7 +62,6 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
GenDns();
GenStatistic();
ApplyOutboundSendThrough();
var finalRule = BuildFinalRule();
if (!string.IsNullOrEmpty(finalRule?.balancerTag))
@ -196,7 +195,6 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
_coreConfig.routing.rules.Add(rule);
}
ApplyOutboundSendThrough();
//ret.Msg =string.Format(ResUI.SuccessfulConfiguration"), node.getSummary());
ret.Success = true;
ret.Data = JsonUtils.Serialize(_coreConfig);
@ -257,7 +255,6 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
});
_coreConfig.routing.rules.Add(BuildFinalRule());
ApplyOutboundSendThrough();
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
@ -378,7 +375,6 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
//_coreConfig.inbounds.Clear();
ApplyOutboundSendThrough();
var configNode = JsonUtils.ParseJson(JsonUtils.Serialize(_coreConfig))!;
configNode["inbounds"]!.AsArray().Add(new
{

View file

@ -127,43 +127,4 @@ public partial class CoreConfigV2rayService
return JsonUtils.Serialize(fullConfigTemplateNode);
}
private void ApplyOutboundSendThrough()
{
var sendThrough = _config.CoreBasicItem.SendThrough?.TrimEx();
foreach (var outbound in _coreConfig.outbounds ?? [])
{
outbound.sendThrough = ShouldApplySendThrough(outbound, sendThrough) ? sendThrough : null;
}
}
private static bool ShouldApplySendThrough(Outbounds4Ray outbound, string? sendThrough)
{
if (sendThrough.IsNullOrEmpty())
{
return false;
}
if (outbound.protocol is "freedom" or "blackhole" or "dns" or "loopback")
{
return false;
}
if (outbound.streamSettings?.sockopt?.dialerProxy.IsNullOrEmpty() == false)
{
return false;
}
var outboundAddress = outbound.settings?.servers?.FirstOrDefault()?.address
?? outbound.settings?.vnext?.FirstOrDefault()?.address
?? outbound.settings?.address?.ToString()
?? string.Empty;
if (outboundAddress.Equals("localhost", StringComparison.OrdinalIgnoreCase))
{
return false;
}
return !IPAddress.TryParse(outboundAddress, out var address) || !IPAddress.IsLoopback(address);
}
}

View file

@ -20,7 +20,6 @@ public class OptionSettingViewModel : MyReactiveObject
[Reactive] public bool defAllowInsecure { get; set; }
[Reactive] public string defFingerprint { get; set; }
[Reactive] public string defUserAgent { get; set; }
[Reactive] public string sendThrough { get; set; }
[Reactive] public string mux4SboxProtocol { get; set; }
[Reactive] public bool enableCacheFile4Sbox { get; set; }
[Reactive] public int? hyUpMbps { get; set; }
@ -155,7 +154,6 @@ public class OptionSettingViewModel : MyReactiveObject
defAllowInsecure = _config.CoreBasicItem.DefAllowInsecure;
defFingerprint = _config.CoreBasicItem.DefFingerprint;
defUserAgent = _config.CoreBasicItem.DefUserAgent;
sendThrough = _config.CoreBasicItem.SendThrough;
mux4SboxProtocol = _config.Mux4SboxItem.Protocol;
enableCacheFile4Sbox = _config.CoreBasicItem.EnableCacheFile4Sbox;
hyUpMbps = _config.HysteriaItem.UpMbps;
@ -299,12 +297,6 @@ public class OptionSettingViewModel : MyReactiveObject
NoticeManager.Instance.Enqueue(ResUI.FillLocalListeningPort);
return;
}
var sendThroughValue = sendThrough?.TrimEx();
if (sendThroughValue.IsNotEmpty() && !Utils.IsIpv4(sendThroughValue))
{
NoticeManager.Instance.Enqueue(ResUI.FillCorrectSendThroughIPv4);
return;
}
var needReboot = EnableStatistics != _config.GuiItem.EnableStatistics
|| DisplayRealTimeSpeed != _config.GuiItem.DisplayRealTimeSpeed
|| EnableDragDropSort != _config.UiItem.EnableDragDropSort
@ -344,7 +336,6 @@ public class OptionSettingViewModel : MyReactiveObject
_config.CoreBasicItem.DefAllowInsecure = defAllowInsecure;
_config.CoreBasicItem.DefFingerprint = defFingerprint;
_config.CoreBasicItem.DefUserAgent = defUserAgent;
_config.CoreBasicItem.SendThrough = sendThrough?.TrimEx();
_config.Mux4SboxItem.Protocol = mux4SboxProtocol;
_config.CoreBasicItem.EnableCacheFile4Sbox = enableCacheFile4Sbox;
_config.HysteriaItem.UpMbps = hyUpMbps ?? 0;

View file

@ -325,27 +325,6 @@
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="21"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsSendThrough}" />
<TextBox
x:Name="txtsendThrough"
Grid.Row="21"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
Watermark="0.0.0.0" />
<TextBlock
Grid.Row="21"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsSendThroughTip}"
TextWrapping="Wrap" />
</Grid>
</ScrollViewer>
</TabItem>

View file

@ -76,7 +76,6 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
this.Bind(ViewModel, vm => vm.defAllowInsecure, v => v.togdefAllowInsecure.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.defFingerprint, v => v.cmbdefFingerprint.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.defUserAgent, v => v.cmbdefUserAgent.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.sendThrough, v => v.txtsendThrough.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.mux4SboxProtocol, v => v.cmbmux4SboxProtocol.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.enableCacheFile4Sbox, v => v.togenableCacheFile4Sbox.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.hyUpMbps, v => v.txtUpMbps.Text).DisposeWith(disposables);

View file

@ -32,8 +32,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHub Action", "GitHub Act
..\.github\workflows\winget-publish.yml = ..\.github\workflows\winget-publish.yml
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceLib.Tests", "ServiceLib.Tests\ServiceLib.Tests.csproj", "{E0B6C5C7-ED48-42EB-947A-877779E9F555}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -60,10 +58,6 @@ Global
{CB3DE54F-3A26-AE02-1299-311132C32156}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB3DE54F-3A26-AE02-1299-311132C32156}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB3DE54F-3A26-AE02-1299-311132C32156}.Release|Any CPU.Build.0 = Release|Any CPU
{E0B6C5C7-ED48-42EB-947A-877779E9F555}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E0B6C5C7-ED48-42EB-947A-877779E9F555}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0B6C5C7-ED48-42EB-947A-877779E9F555}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0B6C5C7-ED48-42EB-947A-877779E9F555}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -16,7 +16,6 @@
</Folder>
<Project Path="AmazTool/AmazTool.csproj" />
<Project Path="GlobalHotKeys/src/GlobalHotKeys/GlobalHotKeys.csproj" />
<Project Path="ServiceLib.Tests/ServiceLib.Tests.csproj" />
<Project Path="ServiceLib/ServiceLib.csproj" />
<Project Path="v2rayN.Desktop/v2rayN.Desktop.csproj" />
<Project Path="v2rayN/v2rayN.csproj" />

View file

@ -391,30 +391,6 @@
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="21"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsSendThrough}" />
<TextBox
x:Name="txtsendThrough"
Grid.Row="21"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefTextBox}"
materialDesign:HintAssist.Hint="0.0.0.0" />
<TextBlock
Grid.Row="21"
Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsSendThroughTip}"
TextWrapping="Wrap" />
</Grid>
</ScrollViewer>
</TabItem>

View file

@ -73,7 +73,6 @@ public partial class OptionSettingWindow
this.Bind(ViewModel, vm => vm.defAllowInsecure, v => v.togdefAllowInsecure.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.defFingerprint, v => v.cmbdefFingerprint.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.defUserAgent, v => v.cmbdefUserAgent.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.sendThrough, v => v.txtsendThrough.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.mux4SboxProtocol, v => v.cmbmux4SboxProtocol.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.enableCacheFile4Sbox, v => v.togenableCacheFile4Sbox.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.hyUpMbps, v => v.txtUpMbps.Text).DisposeWith(disposables);