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)];
}