Refactor profile item config (#8659)

* Refactor

* Add hysteria2 bandwidth and hop interval support

* Upgrade config version and rename

* Refactor id and security

* Refactor flow

* Fix hy2 bbr

* Fix warning CS0618

* Remove unused code

* Fix hy2 migrate

* Fix

* Refactor

* Refactor ProfileItem protocol extra handling

* Refactor, use record instead of class

* Hy2 SalamanderPass

* Fix Tuic

* Fix group

* Fix Tuic

* Fix hy2 Brutal Bandwidth

* Clean Code

* Fix

* Support interval range

* Add Username

---------

Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
This commit is contained in:
DHR60
2026-02-05 11:48:33 +00:00
committed by GitHub
parent d9843dc775
commit 677e81f9a7
40 changed files with 951 additions and 802 deletions
@@ -242,7 +242,7 @@ public partial class CoreConfigSingboxService
}
else if (node?.ConfigType.IsGroupType() == true)
{
var queryServerNames = (await ProfileGroupItemManager.GetAllChildEchQuerySni(node.IndexId)).ToList();
var queryServerNames = (await GroupProfileManager.GetAllChildEchQuerySni(node)).ToList();
if (queryServerNames.Count > 0)
{
singboxConfig.dns.rules.Add(new()
@@ -6,6 +6,7 @@ public partial class CoreConfigSingboxService
{
try
{
var protocolExtra = node.GetProtocolExtra();
outbound.server = node.Address;
outbound.server_port = node.Port;
outbound.type = Global.ProtocolTypes[node.ConfigType];
@@ -14,11 +15,11 @@ public partial class CoreConfigSingboxService
{
case EConfigType.VMess:
{
outbound.uuid = node.Id;
outbound.alter_id = node.AlterId;
if (Global.VmessSecurities.Contains(node.Security))
outbound.uuid = node.Password;
outbound.alter_id = int.TryParse(protocolExtra.AlterId, out var result) ? result : 0;
if (Global.VmessSecurities.Contains(protocolExtra.VmessSecurity))
{
outbound.security = node.Security;
outbound.security = protocolExtra.VmessSecurity;
}
else
{
@@ -31,8 +32,9 @@ public partial class CoreConfigSingboxService
}
case EConfigType.Shadowsocks:
{
outbound.method = AppManager.Instance.GetShadowsocksSecurities(node).Contains(node.Security) ? node.Security : Global.None;
outbound.password = node.Id;
outbound.method = AppManager.Instance.GetShadowsocksSecurities(node).Contains(protocolExtra.SsMethod)
? protocolExtra.SsMethod : Global.None;
outbound.password = node.Password;
if (node.Network == nameof(ETransport.tcp) && node.HeaderType == Global.TcpHeaderHttp)
{
@@ -88,37 +90,37 @@ public partial class CoreConfigSingboxService
case EConfigType.SOCKS:
{
outbound.version = "5";
if (node.Security.IsNotEmpty()
&& node.Id.IsNotEmpty())
if (node.Username.IsNotEmpty()
&& node.Password.IsNotEmpty())
{
outbound.username = node.Security;
outbound.password = node.Id;
outbound.username = node.Username;
outbound.password = node.Password;
}
break;
}
case EConfigType.HTTP:
{
if (node.Security.IsNotEmpty()
&& node.Id.IsNotEmpty())
if (node.Username.IsNotEmpty()
&& node.Password.IsNotEmpty())
{
outbound.username = node.Security;
outbound.password = node.Id;
outbound.username = node.Username;
outbound.password = node.Password;
}
break;
}
case EConfigType.VLESS:
{
outbound.uuid = node.Id;
outbound.uuid = node.Password;
outbound.packet_encoding = "xudp";
if (node.Flow.IsNullOrEmpty())
if (!protocolExtra.Flow.IsNullOrEmpty())
{
await GenOutboundMux(node, outbound);
outbound.flow = protocolExtra.Flow;
}
else
{
outbound.flow = node.Flow;
await GenOutboundMux(node, outbound);
}
await GenOutboundTransport(node, outbound);
@@ -126,7 +128,7 @@ public partial class CoreConfigSingboxService
}
case EConfigType.Trojan:
{
outbound.password = node.Id;
outbound.password = node.Password;
await GenOutboundMux(node, outbound);
await GenOutboundTransport(node, outbound);
@@ -134,23 +136,28 @@ public partial class CoreConfigSingboxService
}
case EConfigType.Hysteria2:
{
outbound.password = node.Id;
outbound.password = node.Password;
if (node.Path.IsNotEmpty())
if (!protocolExtra.SalamanderPass.IsNullOrEmpty())
{
outbound.obfs = new()
{
type = "salamander",
password = node.Path.TrimEx(),
password = protocolExtra.SalamanderPass.TrimEx(),
};
}
outbound.up_mbps = _config.HysteriaItem.UpMbps > 0 ? _config.HysteriaItem.UpMbps : null;
outbound.down_mbps = _config.HysteriaItem.DownMbps > 0 ? _config.HysteriaItem.DownMbps : null;
if (node.Ports.IsNotEmpty() && (node.Ports.Contains(':') || node.Ports.Contains('-') || node.Ports.Contains(',')))
outbound.up_mbps = protocolExtra?.UpMbps is { } su and >= 0
? su
: _config.HysteriaItem.UpMbps;
outbound.down_mbps = protocolExtra?.DownMbps is { } sd and >= 0
? sd
: _config.HysteriaItem.DownMbps;
var ports = protocolExtra?.Ports?.IsNullOrEmpty() == false ? protocolExtra.Ports : null;
if ((!ports.IsNullOrEmpty()) && (ports.Contains(':') || ports.Contains('-') || ports.Contains(',')))
{
outbound.server_port = null;
outbound.server_ports = node.Ports.Split(',')
outbound.server_ports = ports.Split(',')
.Select(p => p.Trim())
.Where(p => p.IsNotEmpty())
.Select(p =>
@@ -159,21 +166,38 @@ public partial class CoreConfigSingboxService
return port.Contains(':') ? port : $"{port}:{port}";
})
.ToList();
outbound.hop_interval = _config.HysteriaItem.HopInterval > 0 ? $"{_config.HysteriaItem.HopInterval}s" : null;
outbound.hop_interval = _config.HysteriaItem.HopInterval >= 5
? $"{_config.HysteriaItem.HopInterval}s"
: $"{Global.Hysteria2DefaultHopInt}s";
if (int.TryParse(protocolExtra.HopInterval, out var hiResult))
{
outbound.hop_interval = hiResult >= 5 ? $"{hiResult}s" : outbound.hop_interval;
}
else if (protocolExtra.HopInterval?.Contains('-') ?? false)
{
// may be a range like 5-10
var parts = protocolExtra.HopInterval.Split('-');
if (parts.Length == 2 && int.TryParse(parts[0], out var hiL) &&
int.TryParse(parts[0], out var hiH))
{
var hi = (hiL + hiH) / 2;
outbound.hop_interval = hi >= 5 ? $"{hi}s" : outbound.hop_interval;
}
}
}
break;
}
case EConfigType.TUIC:
{
outbound.uuid = node.Id;
outbound.password = node.Security;
outbound.uuid = node.Username;
outbound.password = node.Password;
outbound.congestion_control = node.HeaderType;
break;
}
case EConfigType.Anytls:
{
outbound.password = node.Id;
outbound.password = node.Password;
break;
}
}
@@ -191,7 +215,9 @@ public partial class CoreConfigSingboxService
{
try
{
endpoint.address = Utils.String2List(node.RequestHost);
var protocolExtra = node.GetProtocolExtra();
endpoint.address = Utils.String2List(protocolExtra.WgInterfaceAddress);
endpoint.type = Global.ProtocolTypes[node.ConfigType];
switch (node.ConfigType)
@@ -200,16 +226,17 @@ public partial class CoreConfigSingboxService
{
var peer = new Peer4Sbox
{
public_key = node.PublicKey,
reserved = Utils.String2List(node.Path)?.Select(int.Parse).ToList(),
public_key = protocolExtra.WgPublicKey,
pre_shared_key = protocolExtra.WgPresharedKey,
reserved = Utils.String2List(protocolExtra.WgReserved)?.Select(int.Parse).ToList(),
address = node.Address,
port = node.Port,
// TODO default ["0.0.0.0/0", "::/0"]
allowed_ips = new() { "0.0.0.0/0", "::/0" },
};
endpoint.private_key = node.Id;
endpoint.mtu = node.ShortId.IsNullOrEmpty() ? Global.TunMtus.First() : node.ShortId.ToInt();
endpoint.peers = new() { peer };
endpoint.private_key = node.Password;
endpoint.mtu = protocolExtra.WgMtu > 0 ? protocolExtra.WgMtu : Global.TunMtus.First();
endpoint.peers = [peer];
break;
}
}
@@ -453,13 +480,13 @@ public partial class CoreConfigSingboxService
{
return -1;
}
var hasCycle = ProfileGroupItemManager.HasCycle(node.IndexId);
var hasCycle = await GroupProfileManager.HasCycle(node);
if (hasCycle)
{
return -1;
}
var (childProfiles, profileGroupItem) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId);
var (childProfiles, profileExtraItem) = await GroupProfileManager.GetChildProfileItems(node);
if (childProfiles.Count <= 0)
{
return -1;
@@ -467,13 +494,14 @@ public partial class CoreConfigSingboxService
switch (node.ConfigType)
{
case EConfigType.PolicyGroup:
var multipleLoad = profileExtraItem?.MultipleLoad ?? EMultipleLoad.LeastPing;
if (ignoreOriginChain)
{
await GenOutboundsList(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, baseTagName);
await GenOutboundsList(childProfiles, singboxConfig, multipleLoad, baseTagName);
}
else
{
await GenOutboundsListWithChain(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, baseTagName);
await GenOutboundsListWithChain(childProfiles, singboxConfig, multipleLoad, baseTagName);
}
break;
@@ -585,7 +613,7 @@ public partial class CoreConfigSingboxService
if (node.ConfigType.IsGroupType())
{
var (childProfiles, profileGroupItem) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId);
var (childProfiles, profileExtraItem) = await GroupProfileManager.GetChildProfileItems(node);
if (childProfiles.Count <= 0)
{
continue;
@@ -594,7 +622,8 @@ public partial class CoreConfigSingboxService
var ret = node.ConfigType switch
{
EConfigType.PolicyGroup =>
await GenOutboundsListWithChain(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, childBaseTagName),
await GenOutboundsListWithChain(childProfiles, singboxConfig,
profileExtraItem?.MultipleLoad ?? EMultipleLoad.LeastPing, childBaseTagName),
EConfigType.ProxyChain =>
await GenChainOutboundsList(childProfiles, singboxConfig, childBaseTagName),
_ => throw new NotImplementedException()
@@ -763,7 +792,7 @@ public partial class CoreConfigSingboxService
if (node.ConfigType.IsGroupType())
{
var (childProfiles, profileGroupItem) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId);
var (childProfiles, profileExtraItem) = await GroupProfileManager.GetChildProfileItems(node);
if (childProfiles.Count <= 0)
{
continue;
@@ -772,7 +801,7 @@ public partial class CoreConfigSingboxService
var ret = node.ConfigType switch
{
EConfigType.PolicyGroup =>
await GenOutboundsList(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, childBaseTagName),
await GenOutboundsList(childProfiles, singboxConfig, profileExtraItem?.MultipleLoad ?? EMultipleLoad.LeastPing, childBaseTagName),
EConfigType.ProxyChain =>
await GenChainOutboundsList(childProfiles, singboxConfig, childBaseTagName),
_ => throw new NotImplementedException()
@@ -6,6 +6,7 @@ public partial class CoreConfigV2rayService
{
try
{
var protocolExtra = node.GetProtocolExtra();
var muxEnabled = node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled;
switch (node.ConfigType)
{
@@ -35,12 +36,12 @@ public partial class CoreConfigV2rayService
usersItem = vnextItem.users.First();
}
usersItem.id = node.Id;
usersItem.alterId = node.AlterId;
usersItem.id = node.Password;
usersItem.alterId = int.TryParse(protocolExtra?.AlterId, out var result) ? result : 0;
usersItem.email = Global.UserEMail;
if (Global.VmessSecurities.Contains(node.Security))
if (Global.VmessSecurities.Contains(protocolExtra.VmessSecurity))
{
usersItem.security = node.Security;
usersItem.security = protocolExtra.VmessSecurity;
}
else
{
@@ -66,8 +67,9 @@ public partial class CoreConfigV2rayService
}
serversItem.address = node.Address;
serversItem.port = node.Port;
serversItem.password = node.Id;
serversItem.method = AppManager.Instance.GetShadowsocksSecurities(node).Contains(node.Security) ? node.Security : "none";
serversItem.password = node.Password;
serversItem.method = AppManager.Instance.GetShadowsocksSecurities(node).Contains(protocolExtra.SsMethod)
? protocolExtra.SsMethod : "none";
serversItem.ota = false;
serversItem.level = 1;
@@ -95,13 +97,13 @@ public partial class CoreConfigV2rayService
serversItem.method = null;
serversItem.password = null;
if (node.Security.IsNotEmpty()
&& node.Id.IsNotEmpty())
if (node.Username.IsNotEmpty()
&& node.Password.IsNotEmpty())
{
SocksUsersItem4Ray socksUsersItem = new()
{
user = node.Security,
pass = node.Id,
user = node.Username ?? "",
pass = node.Password,
level = 1
};
@@ -138,17 +140,16 @@ public partial class CoreConfigV2rayService
{
usersItem = vnextItem.users.First();
}
usersItem.id = node.Id;
usersItem.id = node.Password;
usersItem.email = Global.UserEMail;
usersItem.encryption = node.Security;
usersItem.encryption = protocolExtra.VlessEncryption;
if (node.Flow.IsNullOrEmpty())
if (!protocolExtra.Flow.IsNullOrEmpty())
{
await GenOutboundMux(node, outbound, muxEnabled, muxEnabled);
usersItem.flow = protocolExtra.Flow;
}
else
{
usersItem.flow = node.Flow;
await GenOutboundMux(node, outbound, false, muxEnabled);
}
outbound.settings.servers = null;
@@ -168,7 +169,7 @@ public partial class CoreConfigV2rayService
}
serversItem.address = node.Address;
serversItem.port = node.Port;
serversItem.password = node.Id;
serversItem.password = node.Password;
serversItem.ota = false;
serversItem.level = 1;
@@ -199,16 +200,16 @@ public partial class CoreConfigV2rayService
}
var peer = new WireguardPeer4Ray
{
publicKey = node.PublicKey,
publicKey = protocolExtra.WgPublicKey ?? "",
endpoint = address + ":" + node.Port.ToString()
};
var setting = new Outboundsettings4Ray
{
address = Utils.String2List(node.RequestHost),
secretKey = node.Id,
reserved = Utils.String2List(node.Path)?.Select(int.Parse).ToList(),
mtu = node.ShortId.IsNullOrEmpty() ? Global.TunMtus.First() : node.ShortId.ToInt(),
peers = new List<WireguardPeer4Ray> { peer }
address = Utils.String2List(protocolExtra.WgInterfaceAddress),
secretKey = node.Password,
reserved = Utils.String2List(protocolExtra.WgReserved)?.Select(int.Parse).ToList(),
mtu = protocolExtra.WgMtu > 0 ? protocolExtra.WgMtu : Global.TunMtus.First(),
peers = [peer]
};
outbound.settings = setting;
outbound.settings.vnext = null;
@@ -509,28 +510,38 @@ public partial class CoreConfigV2rayService
break;
case "hysteria":
var protocolExtra = node.GetProtocolExtra();
var ports = protocolExtra?.Ports;
int? upMbps = protocolExtra?.UpMbps is { } su and >= 0
? su
: _config.HysteriaItem.UpMbps;
int? downMbps = protocolExtra?.DownMbps is { } sd and >= 0
? sd
: _config.HysteriaItem.UpMbps;
var hopInterval = !protocolExtra.HopInterval.IsNullOrEmpty()
? protocolExtra.HopInterval
: (_config.HysteriaItem.HopInterval >= 5
? _config.HysteriaItem.HopInterval
: Global.Hysteria2DefaultHopInt).ToString();
HysteriaUdpHop4Ray? udpHop = null;
if (node.Ports.IsNotEmpty() &&
(node.Ports.Contains(':') || node.Ports.Contains('-') || node.Ports.Contains(',')))
if (!ports.IsNullOrEmpty() &&
(ports.Contains(':') || ports.Contains('-') || ports.Contains(',')))
{
udpHop = new()
udpHop = new HysteriaUdpHop4Ray
{
ports = node.Ports.Replace(':', '-'),
interval = _config.HysteriaItem.HopInterval > 0
? _config.HysteriaItem.HopInterval
: null,
ports = ports.Replace(':', '-'),
interval = hopInterval,
};
}
HysteriaSettings4Ray hysteriaSettings = new()
streamSettings.hysteriaSettings = new()
{
version = 2,
auth = node.Id,
up = _config.HysteriaItem.UpMbps > 0 ? $"{_config.HysteriaItem.UpMbps}mbps" : null,
down = _config.HysteriaItem.DownMbps > 0 ? $"{_config.HysteriaItem.DownMbps}mbps" : null,
auth = node.Password,
up = upMbps > 0 ? $"{upMbps}mbps" : null,
down = downMbps > 0 ? $"{downMbps}mbps" : null,
udphop = udpHop,
};
streamSettings.hysteriaSettings = hysteriaSettings;
if (node.Path.IsNotEmpty())
if (!protocolExtra.SalamanderPass.IsNullOrEmpty())
{
streamSettings.finalmask ??= new();
streamSettings.finalmask.udp =
@@ -538,7 +549,7 @@ public partial class CoreConfigV2rayService
new Mask4Ray
{
type = "salamander",
settings = new MaskSettings4Ray { password = node.Path.TrimEx(), }
settings = new MaskSettings4Ray { password = protocolExtra.SalamanderPass.TrimEx(), }
}
];
}
@@ -592,13 +603,13 @@ public partial class CoreConfigV2rayService
{
return -1;
}
var hasCycle = ProfileGroupItemManager.HasCycle(node.IndexId);
var hasCycle = await GroupProfileManager.HasCycle(node);
if (hasCycle)
{
return -1;
}
var (childProfiles, profileGroupItem) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId);
var (childProfiles, profileExtraItem) = await GroupProfileManager.GetChildProfileItems(node);
if (childProfiles.Count <= 0)
{
return -1;
@@ -627,8 +638,9 @@ public partial class CoreConfigV2rayService
//add balancers
if (node.ConfigType == EConfigType.PolicyGroup)
{
await GenObservatory(v2rayConfig, profileGroupItem.MultipleLoad, baseTagName);
await GenBalancer(v2rayConfig, profileGroupItem.MultipleLoad, baseTagName);
var multipleLoad = profileExtraItem?.MultipleLoad ?? EMultipleLoad.LeastPing;
await GenObservatory(v2rayConfig, multipleLoad, baseTagName);
await GenBalancer(v2rayConfig, multipleLoad, baseTagName);
}
}
catch (Exception ex)
@@ -737,7 +749,7 @@ public partial class CoreConfigV2rayService
if (node.ConfigType.IsGroupType())
{
var (childProfiles, _) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId);
var (childProfiles, _) = await GroupProfileManager.GetChildProfileItems(node);
if (childProfiles.Count <= 0)
{
continue;
@@ -891,7 +903,7 @@ public partial class CoreConfigV2rayService
if (node.ConfigType.IsGroupType())
{
var (childProfiles, _) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId);
var (childProfiles, _) = await GroupProfileManager.GetChildProfileItems(node);
if (childProfiles.Count <= 0)
{
continue;