using MoShiro.Protocol; namespace MoShiro.Measurement; /// /// 一种采集方法(Kind)的两个角色:拨号方(Probe)和监听方(Agent),以及它能不能作为目标任务(Agent 自己探测一个地址,没有对端)运行。 /// 积木只按机制命名、只产生原始列,不知道上层的方案或协议。 /// public sealed record BlockPair( string Kind, Func Dialer, Func? Listener, bool RunsAsTarget = false, bool OnDemandOnly = false, IReadOnlyList? Directions = null) { /// 这个 Kind 支持 吗(没有 direction 参数的 Kind 传 null)。 public bool Supports(string? direction) => Directions is null || direction is null || Directions.Contains(direction); } /// /// 积木目录:新增一种采集方法 = 在 里加一条声明,在这里加一行,实现它的两个角色。Probe 和 Agent 同时获得。 /// hello 里上报的 capabilities、本地预算检查的支持列表都从这里推出来,不再手写。 /// public static class BlockCatalog { public static readonly IReadOnlyList All = [ new("udp_echo", (e, s) => new UdpEchoDialer(e, s), (e, s) => new UdpEchoListener(e, s)), new("tcp_echo", (e, s) => new TcpEchoDialer(e, s), (e, s) => new TcpEchoListener(e, s)), new("udp_train", (e, s) => new TrainDialer(e, s), (e, s) => new TrainListener(e, s), OnDemandOnly: true, Directions: ["rev"]), new("tcp_bulk", (e, s) => new TcpBulkDialer(e, s), (e, s) => new TcpBulkListener(e, s), OnDemandOnly: true, Directions: ["fwd", "rev"]), new("connect", (e, s) => new ConnectDialer(e, s), (e, s) => new IdleListener(e, s), RunsAsTarget: true), new("hold", (e, s) => new HoldDialer(e, s), (e, s) => new TcpEchoListener(e, s, record: false)), new("icmp_echo", (e, s) => new IcmpEchoSolo(e, s), null, RunsAsTarget: true), ]; public static BlockPair? Find(string kind) => All.FirstOrDefault(p => p.Kind == kind); /// 这个构建的 Agent 能运行的 Kind(监听方,或目标任务)。 public static IReadOnlyList AgentKinds { get; } = [.. All.Where(p => p.Listener is not null || p.RunsAsTarget).Select(p => p.Kind)]; /// 这个构建的 Probe 能运行的 Kind(有监听方可以配对的拨号方)。 public static IReadOnlyList ProbeKinds { get; } = [.. All.Where(p => p.Listener is not null).Select(p => p.Kind)]; }