using System.Text.Json; using System.Text.Json.Serialization; using Fleet.Rpc; using Fleet.Server; using MoShiro.Backend.Application; using MoShiro.Protocol; namespace MoShiro.Backend.Gateway; /// /// 期望状态:为每个 Agent 下发完整的 快照(有效任务集 + Probe 公钥)。 /// 节点应用之后回传 applied_version 和 rejected[](unsupported、budget_exceeded、policy_denied),面板上可以看到。 /// public sealed class TaskSetStateProvider : IStateProvider { private readonly TaskPlanner _planner; private readonly IAgentStore _agents; public TaskSetStateProvider(TaskPlanner planner, IAgentStore agents) { _planner = planner; _agents = agents; } public string Type => TaskSet.StateType; public async ValueTask GetAsync(NodeRecord node, CancellationToken ct) { if (node.Id.Value.StartsWith(ProbeId.Prefix, StringComparison.Ordinal)) { return null; // Probe 不运行任务集 } DesiredTaskSet? desired = await _planner.GetDesiredAsync(node.Id, ct); return desired is null ? null : new StateDocument(desired.Version, JsonSerializer.SerializeToElement(desired.Document, MoShiroJsonContext.Default.TaskSet)); } public async ValueTask OnAppliedAsync(NodeRecord node, long version, StateSyncResult result, CancellationToken ct) { string? rejected = result.Rejected.Count == 0 ? null : JsonSerializer.Serialize(result.Rejected, GatewayJson.Default.ListRejectedItem); await _agents.SetAppliedTaskStateAsync(node.Id, result.AppliedVersion, rejected, ct); } } [JsonSerializable(typeof(List))] internal sealed partial class GatewayJson : JsonSerializerContext;