mirror of https://github.com/2dust/v2rayN
Add Detour Feature
parent
eb310e2a1e
commit
f5e82dd2b0
|
@ -13,4 +13,6 @@ public class CustomConfigItem
|
|||
public ECoreType CoreType { get; set; }
|
||||
public string? Config { get; set; }
|
||||
public string? TunConfig { get; set; }
|
||||
public bool? AddProxyOnly { get; set; } = false;
|
||||
public string? ProxyDetour { get; set; }
|
||||
}
|
||||
|
|
|
@ -2247,6 +2247,15 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Do Not Add Non-Proxy Protocol Outbound 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbAddProxyProtocolOutboundOnly {
|
||||
get {
|
||||
return ResourceManager.GetString("TbAddProxyProtocolOutboundOnly", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Address 的本地化字符串。
|
||||
/// </summary>
|
||||
|
@ -2382,24 +2391,6 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable Custom DNS 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbCustomDNSEnable {
|
||||
get {
|
||||
return ResourceManager.GetString("TbCustomDNSEnable", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Custom DNS Enabled, This Page's Settings Invalid 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbCustomDNSEnabledPageInvalid {
|
||||
get {
|
||||
return ResourceManager.GetString("TbCustomDNSEnabledPageInvalid", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable Custom Config 的本地化字符串。
|
||||
/// </summary>
|
||||
|
@ -2418,6 +2409,24 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable Custom DNS 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbCustomDNSEnable {
|
||||
get {
|
||||
return ResourceManager.GetString("TbCustomDNSEnable", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Custom DNS Enabled, This Page's Settings Invalid 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbCustomDNSEnabledPageInvalid {
|
||||
get {
|
||||
return ResourceManager.GetString("TbCustomDNSEnabledPageInvalid", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Display GUI 的本地化字符串。
|
||||
/// </summary>
|
||||
|
@ -2761,7 +2770,7 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Override Outbound Config, routing.balancers and routing.rules.outboundTag Only 的本地化字符串。
|
||||
/// 查找类似 Add Outbound Config Only, routing.balancers and routing.rules.outboundTag 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbRayCustomConfigDesc {
|
||||
get {
|
||||
|
@ -2895,6 +2904,15 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add Outbound and Endpoint Config Only 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSBCustomConfigDesc {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSBCustomConfigDesc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 sing-box Direct Resolution Strategy 的本地化字符串。
|
||||
/// </summary>
|
||||
|
@ -2958,15 +2976,6 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Override Outbound And Endpoint Config Only 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSBCustomConfigDesc {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSBCustomConfigDesc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Encryption method (security) 的本地化字符串。
|
||||
/// </summary>
|
||||
|
@ -3750,6 +3759,15 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Set Upstream Proxy Tag 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSetUpstreamProxyDetour {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSetUpstreamProxyDetour", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Short Id 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
|
@ -1483,9 +1483,15 @@
|
|||
<value>sing-box Custom Config</value>
|
||||
</data>
|
||||
<data name="TbRayCustomConfigDesc" xml:space="preserve">
|
||||
<value>Override Outbound Config, routing.balancers and routing.rules.outboundTag Only</value>
|
||||
<value>Add Outbound Config Only, routing.balancers and routing.rules.outboundTag</value>
|
||||
</data>
|
||||
<data name="TbSBCustomConfigDesc" xml:space="preserve">
|
||||
<value>Override Outbound And Endpoint Config Only</value>
|
||||
<value>Add Outbound and Endpoint Config Only</value>
|
||||
</data>
|
||||
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
|
||||
<value>Do Not Add Non-Proxy Protocol Outbound</value>
|
||||
</data>
|
||||
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
|
||||
<value>Set Upstream Proxy Tag</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1483,9 +1483,15 @@
|
|||
<value>sing-box Custom Config</value>
|
||||
</data>
|
||||
<data name="TbRayCustomConfigDesc" xml:space="preserve">
|
||||
<value>Override Outbound Config, routing.balancers and routing.rules.outboundTag Only</value>
|
||||
<value>Add Outbound Config Only, routing.balancers and routing.rules.outboundTag</value>
|
||||
</data>
|
||||
<data name="TbSBCustomConfigDesc" xml:space="preserve">
|
||||
<value>Override Outbound And Endpoint Config Only</value>
|
||||
<value>Add Outbound and Endpoint Config Only</value>
|
||||
</data>
|
||||
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
|
||||
<value>Do Not Add Non-Proxy Protocol Outbound</value>
|
||||
</data>
|
||||
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
|
||||
<value>Set Upstream Proxy Tag</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1483,9 +1483,15 @@
|
|||
<value>sing-box Custom Config</value>
|
||||
</data>
|
||||
<data name="TbRayCustomConfigDesc" xml:space="preserve">
|
||||
<value>Override Outbound Config, routing.balancers and routing.rules.outboundTag Only</value>
|
||||
<value>Add Outbound Config Only, routing.balancers and routing.rules.outboundTag</value>
|
||||
</data>
|
||||
<data name="TbSBCustomConfigDesc" xml:space="preserve">
|
||||
<value>Override Outbound And Endpoint Config Only</value>
|
||||
<value>Add Outbound and Endpoint Config Only</value>
|
||||
</data>
|
||||
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
|
||||
<value>Do Not Add Non-Proxy Protocol Outbound</value>
|
||||
</data>
|
||||
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
|
||||
<value>Set Upstream Proxy Tag</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1483,9 +1483,15 @@
|
|||
<value>sing-box Custom Config</value>
|
||||
</data>
|
||||
<data name="TbRayCustomConfigDesc" xml:space="preserve">
|
||||
<value>Override Outbound Config, routing.balancers and routing.rules.outboundTag Only</value>
|
||||
<value>Add Outbound Config Only, routing.balancers and routing.rules.outboundTag</value>
|
||||
</data>
|
||||
<data name="TbSBCustomConfigDesc" xml:space="preserve">
|
||||
<value>Override Outbound And Endpoint Config Only</value>
|
||||
<value>Add Outbound and Endpoint Config Only</value>
|
||||
</data>
|
||||
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
|
||||
<value>Do Not Add Non-Proxy Protocol Outbound</value>
|
||||
</data>
|
||||
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
|
||||
<value>Set Upstream Proxy Tag</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1480,9 +1480,15 @@
|
|||
<value>sing-box 自定义配置</value>
|
||||
</data>
|
||||
<data name="TbRayCustomConfigDesc" xml:space="preserve">
|
||||
<value>仅覆盖出站配置,routing.balancers 和 routing.rules.outboundTag</value>
|
||||
<value>仅添加出站配置,routing.balancers 和 routing.rules.outboundTag</value>
|
||||
</data>
|
||||
<data name="TbSBCustomConfigDesc" xml:space="preserve">
|
||||
<value>仅覆盖出站和端点配置</value>
|
||||
<value>仅添加出站和端点配置</value>
|
||||
</data>
|
||||
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
|
||||
<value>不添加非代理协议出站</value>
|
||||
</data>
|
||||
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
|
||||
<value>设置上游代理 tag</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1480,9 +1480,15 @@
|
|||
<value>sing-box Custom Config</value>
|
||||
</data>
|
||||
<data name="TbRayCustomConfigDesc" xml:space="preserve">
|
||||
<value>Override Outbound Config, routing.balancers and routing.rules.outboundTag Only</value>
|
||||
<value>Add Outbound Config Only, routing.balancers and routing.rules.outboundTag</value>
|
||||
</data>
|
||||
<data name="TbSBCustomConfigDesc" xml:space="preserve">
|
||||
<value>Override Outbound And Endpoint Config Only</value>
|
||||
<value>Add Outbound and Endpoint Config Only</value>
|
||||
</data>
|
||||
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
|
||||
<value>Do Not Add Non-Proxy Protocol Outbound</value>
|
||||
</data>
|
||||
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
|
||||
<value>Set Upstream Proxy Tag</value>
|
||||
</data>
|
||||
</root>
|
|
@ -86,43 +86,7 @@ public class CoreConfigSingboxService
|
|||
ret.Success = true;
|
||||
|
||||
var customConfig = await AppHandler.Instance.GetCustomConfigItem(ECoreType.sing_box);
|
||||
var customConfigItem = customConfig.Config;
|
||||
if (_config.TunModeItem.EnableTun)
|
||||
{
|
||||
customConfigItem = customConfig.TunConfig;
|
||||
}
|
||||
if (customConfig.Enabled && (!customConfigItem.IsNullOrEmpty()))
|
||||
{
|
||||
var customConfigNode = JsonNode.Parse(customConfigItem);
|
||||
if (customConfigNode != null)
|
||||
{
|
||||
if (customConfigNode["outbounds"] is JsonArray customOutboundsNode)
|
||||
{
|
||||
if (JsonNode.Parse(JsonUtils.Serialize(singboxConfig.outbounds)) is JsonArray newOutbounds)
|
||||
{
|
||||
foreach (var outbound in newOutbounds)
|
||||
{
|
||||
customOutboundsNode.Add(outbound?.DeepClone());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (customConfigNode["endpoints"] is JsonArray customEndpointsNode)
|
||||
{
|
||||
if (singboxConfig.endpoints != null && JsonNode.Parse(JsonUtils.Serialize(singboxConfig.endpoints)) is JsonArray newEndpoints)
|
||||
{
|
||||
foreach (var endpoint in newEndpoints)
|
||||
{
|
||||
customEndpointsNode.Add(endpoint?.DeepClone());
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.Data = JsonUtils.Serialize(customConfigNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.Data = JsonUtils.Serialize(singboxConfig);
|
||||
}
|
||||
ret.Data = await ApplyCustomConfig(customConfig, singboxConfig);
|
||||
return ret;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -476,43 +440,7 @@ public class CoreConfigSingboxService
|
|||
ret.Success = true;
|
||||
|
||||
var customConfig = await AppHandler.Instance.GetCustomConfigItem(ECoreType.sing_box);
|
||||
var customConfigItem = customConfig.Config;
|
||||
if (_config.TunModeItem.EnableTun)
|
||||
{
|
||||
customConfigItem = customConfig.TunConfig;
|
||||
}
|
||||
if (customConfig.Enabled && (!customConfigItem.IsNullOrEmpty()))
|
||||
{
|
||||
var customConfigNode = JsonNode.Parse(customConfigItem);
|
||||
if (customConfigNode != null)
|
||||
{
|
||||
if (customConfigNode["outbounds"] is JsonArray customOutboundsNode)
|
||||
{
|
||||
if (JsonNode.Parse(JsonUtils.Serialize(singboxConfig.outbounds)) is JsonArray newOutbounds)
|
||||
{
|
||||
foreach (var outbound in newOutbounds)
|
||||
{
|
||||
customOutboundsNode.Add(outbound?.DeepClone());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (customConfigNode["endpoints"] is JsonArray customEndpointsNode)
|
||||
{
|
||||
if (singboxConfig.endpoints != null && JsonNode.Parse(JsonUtils.Serialize(singboxConfig.endpoints)) is JsonArray newEndpoints)
|
||||
{
|
||||
foreach (var endpoint in newEndpoints)
|
||||
{
|
||||
customEndpointsNode.Add(endpoint?.DeepClone());
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.Data = JsonUtils.Serialize(customConfigNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.Data = JsonUtils.Serialize(singboxConfig);
|
||||
}
|
||||
ret.Data = await ApplyCustomConfig(customConfig, singboxConfig);
|
||||
return ret;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -2277,5 +2205,61 @@ public class CoreConfigSingboxService
|
|||
return 0;
|
||||
}
|
||||
|
||||
private async Task<string> ApplyCustomConfig(CustomConfigItem customConfig, SingboxConfig singboxConfig)
|
||||
{
|
||||
var customConfigItem = customConfig.Config;
|
||||
if (_config.TunModeItem.EnableTun)
|
||||
{
|
||||
customConfigItem = customConfig.TunConfig;
|
||||
}
|
||||
|
||||
if (!customConfig.Enabled || customConfigItem.IsNullOrEmpty())
|
||||
{
|
||||
return JsonUtils.Serialize(singboxConfig);
|
||||
}
|
||||
|
||||
var customConfigNode = JsonNode.Parse(customConfigItem);
|
||||
if (customConfigNode == null)
|
||||
{
|
||||
return JsonUtils.Serialize(singboxConfig);
|
||||
}
|
||||
|
||||
// Process outbounds
|
||||
var customOutboundsNode = customConfigNode["outbounds"] is JsonArray outbounds ? outbounds : new JsonArray();
|
||||
foreach (var outbound in singboxConfig.outbounds)
|
||||
{
|
||||
if (outbound.type.ToLower() is "direct" or "block")
|
||||
{
|
||||
if (customConfig.AddProxyOnly == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (outbound.detour.IsNullOrEmpty() && (!customConfig.ProxyDetour.IsNullOrEmpty()))
|
||||
{
|
||||
outbound.detour = customConfig.ProxyDetour;
|
||||
}
|
||||
customOutboundsNode.Add(JsonUtils.DeepCopy(outbound));
|
||||
}
|
||||
customConfigNode["outbounds"] = customOutboundsNode;
|
||||
|
||||
// Process endpoints
|
||||
if (singboxConfig.endpoints != null && singboxConfig.endpoints.Count > 0)
|
||||
{
|
||||
var customEndpointsNode = customConfigNode["endpoints"] is JsonArray endpoints ? endpoints : new JsonArray();
|
||||
foreach (var endpoint in singboxConfig.endpoints)
|
||||
{
|
||||
if (endpoint.detour.IsNullOrEmpty() && (!customConfig.ProxyDetour.IsNullOrEmpty()))
|
||||
{
|
||||
endpoint.detour = customConfig.ProxyDetour;
|
||||
}
|
||||
customEndpointsNode.Add(JsonUtils.DeepCopy(endpoint));
|
||||
}
|
||||
customConfigNode["endpoints"] = customEndpointsNode;
|
||||
}
|
||||
|
||||
return await Task.FromResult(JsonUtils.Serialize(customConfigNode));
|
||||
}
|
||||
|
||||
#endregion private gen function
|
||||
}
|
||||
|
|
|
@ -71,28 +71,7 @@ public class CoreConfigV2rayService
|
|||
ret.Success = true;
|
||||
|
||||
var customConfig = await AppHandler.Instance.GetCustomConfigItem(ECoreType.Xray);
|
||||
if (customConfig.Enabled && (!customConfig.Config.IsNullOrEmpty()))
|
||||
{
|
||||
var customConfigNode = JsonNode.Parse(customConfig.Config);
|
||||
if (customConfigNode != null)
|
||||
{
|
||||
if (customConfigNode["outbounds"] is JsonArray customOutboundsNode)
|
||||
{
|
||||
if (JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.outbounds)) is JsonArray newOutbounds)
|
||||
{
|
||||
foreach (var outbound in newOutbounds)
|
||||
{
|
||||
customOutboundsNode.Add(outbound?.DeepClone());
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.Data = JsonUtils.Serialize(customConfigNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.Data = JsonUtils.Serialize(v2rayConfig);
|
||||
}
|
||||
ret.Data = await ApplyCustomConfig(customConfig, v2rayConfig);
|
||||
return ret;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -223,64 +202,7 @@ public class CoreConfigV2rayService
|
|||
ret.Success = true;
|
||||
|
||||
var customConfig = await AppHandler.Instance.GetCustomConfigItem(ECoreType.Xray);
|
||||
if (customConfig.Enabled && (!customConfig.Config.IsNullOrEmpty()))
|
||||
{
|
||||
var customConfigNode = JsonNode.Parse(customConfig.Config);
|
||||
if (customConfigNode != null)
|
||||
{
|
||||
var rulesNode = customConfigNode["routing"]?["rules"];
|
||||
if (rulesNode != null)
|
||||
{
|
||||
foreach (var rule in rulesNode.AsArray())
|
||||
{
|
||||
if (rule["outboundTag"]?.GetValue<string>() == Global.ProxyTag)
|
||||
{
|
||||
rule["outboundTag"] = null;
|
||||
rule["balancerTag"] = balancer.tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure routing node exists
|
||||
if (customConfigNode["routing"] == null)
|
||||
{
|
||||
customConfigNode["routing"] = new JsonObject();
|
||||
}
|
||||
|
||||
// Handle balancers - append instead of override
|
||||
if (customConfigNode["routing"]["balancers"] is JsonArray customBalancersNode)
|
||||
{
|
||||
if (JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.routing.balancers)) is JsonArray newBalancers)
|
||||
{
|
||||
foreach (var balancerNode in newBalancers)
|
||||
{
|
||||
customBalancersNode.Add(balancerNode?.DeepClone());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
customConfigNode["routing"]["balancers"] = JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.routing.balancers));
|
||||
}
|
||||
|
||||
// append outbounds instead of override
|
||||
if (customConfigNode["outbounds"] is JsonArray customOutboundsNode)
|
||||
{
|
||||
if (JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.outbounds)) is JsonArray newOutbounds)
|
||||
{
|
||||
foreach (var outbound in newOutbounds)
|
||||
{
|
||||
customOutboundsNode.Add(outbound?.DeepClone());
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.Data = JsonUtils.Serialize(customConfigNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.Data = JsonUtils.Serialize(v2rayConfig);
|
||||
}
|
||||
ret.Data = await ApplyCustomConfig(customConfig, v2rayConfig, true);
|
||||
return ret;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -1921,5 +1843,83 @@ public class CoreConfigV2rayService
|
|||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private async Task<string> ApplyCustomConfig(CustomConfigItem customConfig, V2rayConfig v2rayConfig, bool handleBalancerAndRules = false)
|
||||
{
|
||||
if (!customConfig.Enabled || customConfig.Config.IsNullOrEmpty())
|
||||
{
|
||||
return JsonUtils.Serialize(v2rayConfig);
|
||||
}
|
||||
|
||||
var customConfigNode = JsonNode.Parse(customConfig.Config);
|
||||
if (customConfigNode == null)
|
||||
{
|
||||
return JsonUtils.Serialize(v2rayConfig);
|
||||
}
|
||||
|
||||
// Handle balancer and rules modifications (for multiple load scenarios)
|
||||
if (handleBalancerAndRules && v2rayConfig.routing?.balancers?.Count > 0)
|
||||
{
|
||||
var balancer = v2rayConfig.routing.balancers.First();
|
||||
|
||||
// Modify existing rules in custom config
|
||||
var rulesNode = customConfigNode["routing"]?["rules"];
|
||||
if (rulesNode != null)
|
||||
{
|
||||
foreach (var rule in rulesNode.AsArray())
|
||||
{
|
||||
if (rule["outboundTag"]?.GetValue<string>() == Global.ProxyTag)
|
||||
{
|
||||
rule.AsObject().Remove("outboundTag");
|
||||
rule["balancerTag"] = balancer.tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure routing node exists
|
||||
if (customConfigNode["routing"] == null)
|
||||
{
|
||||
customConfigNode["routing"] = new JsonObject();
|
||||
}
|
||||
|
||||
// Handle balancers - append instead of override
|
||||
if (customConfigNode["routing"]["balancers"] is JsonArray customBalancersNode)
|
||||
{
|
||||
if (JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.routing.balancers)) is JsonArray newBalancers)
|
||||
{
|
||||
foreach (var balancerNode in newBalancers)
|
||||
{
|
||||
customBalancersNode.Add(balancerNode?.DeepClone());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
customConfigNode["routing"]["balancers"] = JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.routing.balancers));
|
||||
}
|
||||
}
|
||||
|
||||
// Handle outbounds - append instead of override
|
||||
var customOutboundsNode = customConfigNode["outbounds"] is JsonArray outbounds ? outbounds : new JsonArray();
|
||||
foreach (var outbound in v2rayConfig.outbounds)
|
||||
{
|
||||
if (outbound.protocol.ToLower() is "blackhole" or "dns" or "freedom")
|
||||
{
|
||||
if (customConfig.AddProxyOnly == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if ((outbound.streamSettings?.sockopt?.dialerProxy.IsNullOrEmpty() == true) && (!customConfig.ProxyDetour.IsNullOrEmpty()))
|
||||
{
|
||||
outbound.streamSettings ??= new StreamSettings4Ray();
|
||||
outbound.streamSettings.sockopt ??= new Sockopt4Ray();
|
||||
outbound.streamSettings.sockopt.dialerProxy = customConfig.ProxyDetour;
|
||||
}
|
||||
customOutboundsNode.Add(JsonUtils.DeepCopy(outbound));
|
||||
}
|
||||
|
||||
return await Task.FromResult(JsonUtils.Serialize(customConfigNode));
|
||||
}
|
||||
|
||||
#endregion private gen function
|
||||
}
|
||||
|
|
|
@ -22,6 +22,18 @@ public class CustomConfigViewModel : MyReactiveObject
|
|||
[Reactive]
|
||||
public string CustomTunConfig4Singbox { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool AddProxyOnly4Ray { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool AddProxyOnly4Singbox { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string ProxyDetour4Ray { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string ProxyDetour4Singbox { get; set; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
|
||||
#endregion Reactive
|
||||
|
||||
|
@ -41,11 +53,15 @@ public class CustomConfigViewModel : MyReactiveObject
|
|||
var item = await AppHandler.Instance.GetCustomConfigItem(ECoreType.Xray);
|
||||
EnableCustomConfig4Ray = item?.Enabled ?? false;
|
||||
CustomConfig4Ray = item?.Config ?? string.Empty;
|
||||
AddProxyOnly4Ray = item?.AddProxyOnly ?? false;
|
||||
ProxyDetour4Ray = item?.ProxyDetour ?? string.Empty;
|
||||
|
||||
var item2 = await AppHandler.Instance.GetCustomConfigItem(ECoreType.sing_box);
|
||||
EnableCustomConfig4Singbox = item2?.Enabled ?? false;
|
||||
CustomConfig4Singbox = item2?.Config ?? string.Empty;
|
||||
CustomTunConfig4Singbox = item2?.TunConfig ?? string.Empty;
|
||||
AddProxyOnly4Singbox = item2?.AddProxyOnly ?? false;
|
||||
ProxyDetour4Singbox = item2?.ProxyDetour ?? string.Empty;
|
||||
}
|
||||
|
||||
private async Task SaveSettingAsync()
|
||||
|
@ -66,10 +82,10 @@ public class CustomConfigViewModel : MyReactiveObject
|
|||
item.Enabled = EnableCustomConfig4Ray;
|
||||
item.Config = null;
|
||||
|
||||
if (CustomConfig4Ray.IsNotEmpty())
|
||||
{
|
||||
item.Config = CustomConfig4Ray;
|
||||
}
|
||||
item.Config = CustomConfig4Ray;
|
||||
|
||||
item.AddProxyOnly = AddProxyOnly4Ray;
|
||||
item.ProxyDetour = ProxyDetour4Ray;
|
||||
|
||||
await ConfigHandler.SaveCustomConfigItem(_config, item);
|
||||
return true;
|
||||
|
@ -82,25 +98,13 @@ public class CustomConfigViewModel : MyReactiveObject
|
|||
item.Config = null;
|
||||
item.TunConfig = null;
|
||||
|
||||
var hasChanges = false;
|
||||
item.Config = CustomConfig4Singbox;
|
||||
item.TunConfig = CustomTunConfig4Singbox;
|
||||
|
||||
if (CustomConfig4Singbox.IsNotEmpty())
|
||||
{
|
||||
item.Config = CustomConfig4Singbox;
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
if (CustomTunConfig4Singbox.IsNotEmpty())
|
||||
{
|
||||
item.TunConfig = CustomTunConfig4Singbox;
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
if (hasChanges)
|
||||
{
|
||||
await ConfigHandler.SaveCustomConfigItem(_config, item);
|
||||
}
|
||||
item.AddProxyOnly = AddProxyOnly4Singbox;
|
||||
item.ProxyDetour = ProxyDetour4Singbox;
|
||||
|
||||
await ConfigHandler.SaveCustomConfigItem(_config, item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,30 @@
|
|||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbAddProxyProtocolOutboundOnly}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togAddProxyProtocolOutboundOnly4Ray"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSetUpstreamProxyDetour}" />
|
||||
<TextBox
|
||||
x:Name="txtProxyDetour4Ray"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</StackPanel>
|
||||
</WrapPanel>
|
||||
|
||||
<HeaderedContentControl
|
||||
Margin="{StaticResource Margin4}"
|
||||
BorderBrush="Gray"
|
||||
|
@ -97,6 +121,30 @@
|
|||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbAddProxyProtocolOutboundOnly}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togAddProxyProtocolOutboundOnly4Singbox"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSetUpstreamProxyDetour}" />
|
||||
<TextBox
|
||||
x:Name="txtProxyDetour4Singbox"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</StackPanel>
|
||||
</WrapPanel>
|
||||
|
||||
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="*,10,*">
|
||||
|
||||
<HeaderedContentControl
|
||||
|
|
|
@ -21,9 +21,13 @@ public partial class CustomConfigWindow : WindowBase<CustomConfigViewModel>
|
|||
{
|
||||
this.Bind(ViewModel, vm => vm.EnableCustomConfig4Ray, v => v.rayCustomConfigEnable.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CustomConfig4Ray, v => v.rayCustomConfig.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AddProxyOnly4Ray, v => v.togAddProxyProtocolOutboundOnly4Ray.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.ProxyDetour4Ray, v => v.txtProxyDetour4Ray.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableCustomConfig4Singbox, v => v.sbCustomConfigEnable.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CustomConfig4Singbox, v => v.sbCustomConfig.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CustomTunConfig4Singbox, v => v.sbCustomTunConfig.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AddProxyOnly4Singbox, v => v.togAddProxyProtocolOutboundOnly4Singbox.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.ProxyDetour4Singbox, v => v.txtProxyDetour4Singbox.Text).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
|
|
|
@ -71,6 +71,33 @@
|
|||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbAddProxyProtocolOutboundOnly}" />
|
||||
<ToggleButton
|
||||
x:Name="togAddProxyProtocolOutboundOnly4Ray"
|
||||
Margin="{StaticResource Margin8}"
|
||||
HorizontalAlignment="Left" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSetUpstreamProxyDetour}" />
|
||||
<TextBox
|
||||
x:Name="txtProxyDetour4Ray"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin8}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
</StackPanel>
|
||||
</WrapPanel>
|
||||
|
||||
<TextBox
|
||||
x:Name="rayCustomConfig"
|
||||
Margin="{StaticResource Margin8}"
|
||||
|
@ -113,6 +140,33 @@
|
|||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbAddProxyProtocolOutboundOnly}" />
|
||||
<ToggleButton
|
||||
x:Name="togAddProxyProtocolOutboundOnly4Singbox"
|
||||
Margin="{StaticResource Margin8}"
|
||||
HorizontalAlignment="Left" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSetUpstreamProxyDetour}" />
|
||||
<TextBox
|
||||
x:Name="txtProxyDetour4Singbox"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin8}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
</StackPanel>
|
||||
</WrapPanel>
|
||||
|
||||
<Grid Margin="{StaticResource Margin8}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
|
|
|
@ -21,9 +21,13 @@ public partial class CustomConfigWindow
|
|||
{
|
||||
this.Bind(ViewModel, vm => vm.EnableCustomConfig4Ray, v => v.rayCustomConfigEnable.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CustomConfig4Ray, v => v.rayCustomConfig.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AddProxyOnly4Ray, v => v.togAddProxyProtocolOutboundOnly4Ray.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.ProxyDetour4Ray, v => v.txtProxyDetour4Ray.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableCustomConfig4Singbox, v => v.sbCustomConfigEnable.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CustomConfig4Singbox, v => v.sbCustomConfig.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CustomTunConfig4Singbox, v => v.sbCustomTunConfig.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AddProxyOnly4Singbox, v => v.togAddProxyProtocolOutboundOnly4Singbox.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.ProxyDetour4Singbox, v => v.txtProxyDetour4Singbox.Text).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue