Files
MoShiro/backend/shared/MoShiro.Protocol/Raw/RawChunk.cs
T
justme 0eda0600cc
ci/woodpecker/pr/verify Pipeline was successful
ci/woodpecker/pr/web-build Pipeline was successful
shared: add independent IPv4 and IPv6 collection [CI]
2026-10-07 11:44:01 +08:00

215 lines
5.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Text.Json;
using System.Text.Json.Serialization;
using Fleet.Core;
namespace MoShiro.Protocol;
/// <summary>Agent 单调时钟与 UTC 的锚点,以及 Probe 时钟相对 Agent 时钟的偏移估计。</summary>
public sealed class ChunkClock
{
[JsonPropertyName("agent_mono_us")]
public long AgentMonoUs { get; set; }
[JsonPropertyName("utc_ms")]
public long UtcMs { get; set; }
/// <summary>Agent 时钟 − Probe 时钟(微秒)。</summary>
[JsonPropertyName("probe_offset_us")]
public long ProbeOffsetUs { get; set; }
/// <summary>Probe 相对 Agent 的时钟漂移(ppb,十亿分之一)。</summary>
[JsonPropertyName("probe_drift_ppb")]
public long ProbeDriftPpb { get; set; }
}
public sealed class ColumnHeader
{
[JsonPropertyName("name")]
public string Name { get; set; } = "";
/// <summary>u8 | u16 | u32 | u64 | i32 | i64</summary>
[JsonPropertyName("type")]
public string Type { get; set; } = "";
/// <summary>plain | delta</summary>
[JsonPropertyName("enc")]
public string Enc { get; set; } = "plain";
[JsonPropertyName("nullable")]
public bool Nullable { get; set; }
/// <summary>ts_probe | ts_agent | ts_local,其他为空。</summary>
[JsonPropertyName("role")]
public string? Role { get; set; }
}
public sealed class StreamHeader
{
[JsonPropertyName("name")]
public string Name { get; set; } = "";
[JsonPropertyName("count")]
public int Count { get; set; }
[JsonPropertyName("columns")]
public List<ColumnHeader> Columns { get; set; } = [];
}
/// <summary>块头(JSON,自描述):列定义写在块里,新增列或新增 Kind 不需要升级 container_version。</summary>
public sealed class RawChunkHeader
{
[JsonPropertyName("ip_version")]
[JsonPropertyOrder(1)]
public string IpVersion { get; set; } = IpVersions.V4;
[JsonPropertyName("chunk_id")]
public ChunkId ChunkId { get; set; }
[JsonPropertyName("container_version")]
public int ContainerVersion { get; set; } = ProtocolVersion.Container;
[JsonPropertyName("kind")]
public string Kind { get; set; } = "";
[JsonPropertyName("task_id")]
public TaskId? TaskId { get; set; }
[JsonPropertyName("test_id")]
public TestId? TestId { get; set; }
[JsonPropertyName("phase")]
public int? Phase { get; set; }
[JsonPropertyName("agent_id")]
public NodeId AgentId { get; set; }
[JsonPropertyName("probe_id")]
public ProbeId? ProbeId { get; set; }
[JsonPropertyName("target")]
public string? Target { get; set; }
/// <summary>参数的完整快照(包含默认值)。</summary>
[JsonPropertyName("params")]
public Dictionary<string, JsonElement> Params { get; set; } = [];
[JsonPropertyName("port")]
public int Port { get; set; }
[JsonPropertyName("direction")]
public string? Direction { get; set; }
[JsonPropertyName("start_utc_ms")]
public long StartUtcMs { get; set; }
[JsonPropertyName("duration_ms")]
public int DurationMs { get; set; }
/// <summary>Probe 一侧的列没有在宽限期内送达:只有 Agent 一侧的数据。</summary>
[JsonPropertyName("partial")]
public bool Partial { get; set; }
[JsonPropertyName("clock")]
public ChunkClock Clock { get; set; } = new();
[JsonPropertyName("streams")]
public List<StreamHeader> Streams { get; set; } = [];
/// <summary>
/// "line:&lt;probe_id&gt;" 或 "target:&lt;task_id&gt;":存储和分析用的序列标识。
/// 同一个 Agent 上每个 Probe 的每种地址族各是一个序列,IPv6 追加 :ipv6,互不混合。
/// </summary>
[JsonIgnore]
public string Series => TaskId is { } id && Target is not null ? "target:" + id.Value : IpVersions.LineSeries(ProbeId?.Value ?? "", IpVersion);
public const string LinePrefix = "line:";
}
public sealed class RawColumn
{
public RawColumn(string name, ColumnType type, ColumnEnc enc, bool nullable, ColumnRole role, long[] values, bool[]? valid)
{
Name = name;
Type = type;
Enc = enc;
Nullable = nullable;
Role = role;
Values = values;
Valid = valid;
}
public string Name { get; }
public ColumnType Type { get; }
public ColumnEnc Enc { get; }
public bool Nullable { get; }
public ColumnRole Role { get; }
/// <summary>所有列统一用 long 存放(u64 按位保存)。缺失值对应的位置内容无意义,请先看 <see cref="IsValid"/>。</summary>
public long[] Values { get; }
public bool[]? Valid { get; }
public int Count => Values.Length;
public bool IsValid(int row) => Valid is null || Valid[row];
}
public sealed class RawStream
{
public RawStream(string name, int count, IReadOnlyList<RawColumn> columns)
{
Name = name;
Count = count;
Columns = columns;
}
public string Name { get; }
public int Count { get; }
public IReadOnlyList<RawColumn> Columns { get; }
public RawColumn? Find(string name)
{
foreach (RawColumn column in Columns)
{
if (column.Name == name)
{
return column;
}
}
return null;
}
}
public sealed class RawChunk
{
public RawChunk(RawChunkHeader header, IReadOnlyList<RawStream> streams)
{
Header = header;
Streams = streams;
}
public RawChunkHeader Header { get; }
public IReadOnlyList<RawStream> Streams { get; }
public RawStream? Find(string name)
{
foreach (RawStream stream in Streams)
{
if (stream.Name == name)
{
return stream;
}
}
return null;
}
}