Files
MoShiro/backend/shared/MoShiro.Measurement/Blocks/BlockCatalog.cs
T
justme ad5efc62ff agent: unify listening and dialing with directed mutual measurements
Replace Probe with Agent across node runtime, Fleet contracts, backend state, API and storage. Report incoming sessions and outgoing link health through each Agent uplink, and retain directed link controls and retry.

Update protocol fixtures and end-to-end coverage for the unified model; accept requested cancellation during the Fleet timeout test cleanup.
2026-10-21 11:55:36 +08:00

49 lines
2.8 KiB
C#

using MoShiro.Protocol;
namespace MoShiro.Measurement;
/// <summary>
/// 一种采集方法(Kind)的两个角色:拨号方和监听方,以及它能不能作为目标任务(节点自己探测一个地址,没有对端)运行。
/// 积木只按机制命名、只产生原始列,不知道上层的方案或协议。
/// </summary>
public sealed record BlockPair(
string Kind,
Func<BlockEnv, BlockSpec, IBlock> Dialer,
Func<BlockEnv, BlockSpec, IBlock>? Listener,
bool RunsAsTarget = false,
bool OnDemandOnly = false,
IReadOnlyList<string>? Directions = null)
{
/// <summary>这个 Kind 支持 <paramref name="direction"/> 吗(没有 <c>direction</c> 参数的 Kind 传 null)。</summary>
public bool Supports(string? direction) => Directions is null || direction is null || Directions.Contains(direction);
}
/// <summary>
/// 积木目录:新增一种采集方法 = 在 <see cref="Kinds"/> 里加一条声明,在这里加一行,实现它的两个角色。所有节点同时获得。
/// hello 里上报的 capabilities、本地预算检查的支持列表都从这里推出来,不再手写。
/// </summary>
public static class BlockCatalog
{
public static readonly IReadOnlyList<BlockPair> All =
[
new("udp_echo", (e, s) => new DatagramEchoDialer(e, s), (e, s) => new DatagramEchoListener(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);
/// <summary>不监听的节点能运行的 Kind:只有目标任务(节点自己探测一个地址)。</summary>
public static IReadOnlyList<string> TargetKinds { get; } = [.. All.Where(p => p.RunsAsTarget).Select(p => p.Kind)];
/// <summary>监听的节点能运行的 Kind(监听方,或目标任务)。</summary>
public static IReadOnlyList<string> AgentKinds { get; } = [.. All.Where(p => p.Listener is not null || p.RunsAsTarget).Select(p => p.Kind)];
/// <summary>这个构建能作为拨号方运行的 Kind(有监听方可以配对的拨号方)。</summary>
public static IReadOnlyList<string> DialerKinds { get; } = [.. All.Where(p => p.Listener is not null).Select(p => p.Kind)];
}