using System.Text.Json; using MoShiro.Protocol; namespace MoShiro.Backend.Application; public sealed record PhaseSpec(string Kind, IReadOnlyDictionary Overrides, int DurationSeconds); /// /// 测试方案:业务层的概念,只在 Backend。方案只是若干采集原语(Kind)阶段的编排,采集层(Agent、Measurement)不认识它。 /// 测试方案:多个阶段的 once 任务组合(例如 hy2_ladder 在 10、25、50、100 Mbps 下各跑 10 秒)。 public sealed record PlanSpec(string Id, string Title, string Description, IReadOnlyList Phases); public static class Plans { private static JsonElement N(double value) => JsonSerializer.SerializeToElement(value, PlanJson.Default.Double); private static JsonElement S(string value) => JsonSerializer.SerializeToElement(value, PlanJson.Default.String); private static PhaseSpec Train(double mbps) => new("quic_stream", new Dictionary { ["mbps"] = N(mbps), ["duration_s"] = N(10) }, 10); public static readonly PlanSpec Hy2Ladder = new( "hy2_ladder", "Hysteria2 ladder", "UDP train at 10, 25, 50 and 100 Mbit/s for 10 s each; models Brutal fixed-rate congestion control.", [Train(10), Train(25), Train(50), Train(100)]); public static readonly PlanSpec RealitySession = new( "reality_session", "REALITY session", "Connection establishment, a short (4 s) bulk transfer for the peak throughput and a held connection.", [ new PhaseSpec("tcp_connect", new Dictionary { ["per_minute"] = N(20) }, 30), new PhaseSpec("tcp_transfer", new Dictionary { ["duration_s"] = N(4), ["direction"] = S("rev") }, 4), new PhaseSpec("tls_hold", new Dictionary { ["heartbeat_s"] = N(5) }, 30), ]); public static readonly IReadOnlyList All = [Hy2Ladder, RealitySession]; public static PlanSpec? Find(string id) { foreach (PlanSpec plan in All) { if (plan.Id == id) { return plan; } } return null; } } [System.Text.Json.Serialization.JsonSerializable(typeof(double))] [System.Text.Json.Serialization.JsonSerializable(typeof(string))] internal sealed partial class PlanJson : System.Text.Json.Serialization.JsonSerializerContext;