using System.Text.Json; using MoShiro.Protocol; namespace MoShiro.Backend.Application; public sealed record EffectiveTask( TaskId Id, string Scope, string Kind, string? Target, IReadOnlyDictionary Params, string Schedule, ParamValues Resolved); /// /// 有效任务集:线路任务模板 + 针对单个 Agent 的覆盖 + 该 Agent 的目标任务。 /// 参数经 ParamSpec 校验并补全默认值,Backend 和节点使用同一套规则。 /// public static class EffectiveTasks { public const string LineScope = "line"; public const string TargetScope = "target"; public static IReadOnlyList Compute(IReadOnlyList all, AgentRecord agent, bool filterByAgentKinds) { var result = new List(); var overrides = new Dictionary(); foreach (TaskRecord task in all) { if (task.AgentId == agent.Id && task.BaseTaskId is { } baseId) { overrides[baseId] = task; } } foreach (TaskRecord task in all.OrderBy(t => t.Id.Value, StringComparer.Ordinal)) { if (task.Scope == LineScope && task.AgentId is null) { // 模板:有覆盖时以覆盖为准(覆盖可以停用或改参数) TaskRecord? over = overrides.GetValueOrDefault(task.Id); if (over is not null) { if (over.Enabled) { Add(result, over.Id, task.Scope, over.Kind, null, Merge(task.Params, over.Params), over.Schedule, agent, filterByAgentKinds); } } else if (task.Enabled) { Add(result, task.Id, task.Scope, task.Kind, null, task.Params, task.Schedule, agent, filterByAgentKinds); } } else if (task.Scope == TargetScope && task.AgentId == agent.Id && task.Enabled) { Add(result, task.Id, task.Scope, task.Kind, task.Target, task.Params, task.Schedule, agent, filterByAgentKinds); } } return result; } private static Dictionary Merge(IReadOnlyDictionary baseParams, IReadOnlyDictionary over) { var merged = new Dictionary(baseParams); foreach ((string key, JsonElement value) in over) { merged[key] = value; } return merged; } private static void Add( List result, TaskId id, string scope, string kind, string? target, IReadOnlyDictionary parameters, string schedule, AgentRecord agent, bool filterByAgentKinds) { KindSpec? spec = Kinds.Find(kind); if (spec is null || (filterByAgentKinds && agent.Kinds.Count > 0 && !agent.Kinds.Contains(kind))) { return; } ParamResolution resolved = ParamResolver.Resolve(spec.Params, parameters); if (!resolved.IsValid) { return; } result.Add(new EffectiveTask(id, scope, kind, target, resolved.Values!.Values, schedule, resolved.Values)); } /// 该 Agent 持续线路任务的总带宽(bit/s)。 public static long ContinuousLineBudget(IReadOnlyList tasks) { long total = 0; foreach (EffectiveTask task in tasks) { if (task.Scope == LineScope && task.Schedule == TaskSchedule.Continuous) { total += Kinds.Find(task.Kind)!.BudgetBitsPerSecond(task.Resolved); } } return total; } }