fix(singbox): preserve Hysteria2 hop interval ranges (#10576)

* fix(singbox): use both bounds of Hysteria2 hop interval

* fix(singbox): preserve native Hysteria2 hop interval bounds
This commit is contained in:
shizukunacho
2026-11-13 14:31:53 +08:00
committed by GitHub
parent 6288b3909e
commit 0734317f9f
3 changed files with 30 additions and 4 deletions
@@ -715,6 +715,32 @@ public class CoreConfigSingboxServiceTests
} }
} }
[Test]
[Arguments("5-15", "5s", "15s")]
[Arguments("20-25", "20s", "25s")]
[Arguments("15", "15s", null)]
[Arguments("4-10", "30s", null)]
[Arguments("15-5", "30s", null)]
public async Task GenerateClientConfigContent_Hysteria2HopInterval_ShouldPreserveRange(string interval, string expected, string? expectedMax)
{
var node = Hysteria2Fmt.Resolve("hysteria2://password@example.com:443?mport=20000-50000", out _)!;
node.CoreType = ECoreType.sing_box;
node.SetProtocolExtra(node.GetProtocolExtra() with { HopInterval = interval });
var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box);
config.HysteriaItem.HopInterval = 30;
CoreConfigTestFactory.BindAppManagerConfig(config);
var context = CoreConfigTestFactory.CreateContext(config, node, ECoreType.sing_box);
var result = new CoreConfigSingboxService(context).GenerateClientConfigContent();
await result.Success.Should().BeTrue().Because($"ret msg: {result.Msg}");
var cfg = JsonUtils.Deserialize<SingboxConfig>(result.Data!.ToString())!;
var proxy = cfg.outbounds.First(o => o.tag == Global.ProxyTag);
await proxy.hop_interval.Should().BeEqualTo(expected);
await proxy.hop_interval_max.Should().BeEqualTo(expectedMax);
}
[Test] [Test]
public async Task GenerateClientConfigContent_Hysteria2Realm_ShouldEmitHttpsServerUrl() public async Task GenerateClientConfigContent_Hysteria2Realm_ShouldEmitHttpsServerUrl()
{ {
@@ -133,6 +133,7 @@ public class Outbound4Sbox : BaseServer4Sbox
public int? alter_id { get; set; } public int? alter_id { get; set; }
public string? flow { get; set; } public string? flow { get; set; }
public string? hop_interval { get; set; } public string? hop_interval { get; set; }
public string? hop_interval_max { get; set; }
public int? up_mbps { get; set; } public int? up_mbps { get; set; }
public int? down_mbps { get; set; } public int? down_mbps { get; set; }
public string? auth_str { get; set; } public string? auth_str { get; set; }
@@ -277,13 +277,12 @@ public partial class CoreConfigSingboxService
} }
else if (protocolExtra.HopInterval?.Contains('-') ?? false) else if (protocolExtra.HopInterval?.Contains('-') ?? false)
{ {
// may be a range like 5-10
var parts = protocolExtra.HopInterval.Split('-'); var parts = protocolExtra.HopInterval.Split('-');
if (parts.Length == 2 && int.TryParse(parts[0], out var hiL) && if (parts.Length == 2 && int.TryParse(parts[0], out var hiL) &&
int.TryParse(parts[0], out var hiH)) int.TryParse(parts[1], out var hiH) && hiL >= 5 && hiH >= hiL)
{ {
var hi = (hiL + hiH) / 2; outbound.hop_interval = $"{hiL}s";
outbound.hop_interval = hi >= 5 ? $"{hi}s" : outbound.hop_interval; outbound.hop_interval_max = $"{hiH}s";
} }
} }
} }