ci/woodpecker/push/main-amd64-build Pipeline was successful
Namespaces, assemblies, solution, binaries, images, systemd units, config paths, environment variables, protocol methods and the Linux user are all renamed. Breaking: existing databases, node identities and installed units must be recreated.
115 lines
3.8 KiB
C#
115 lines
3.8 KiB
C#
using System.Text.Json;
|
|
using MoShiro.Protocol;
|
|
|
|
namespace MoShiro.Backend.Application;
|
|
|
|
public sealed record EffectiveTask(
|
|
TaskId Id,
|
|
string Scope,
|
|
string Kind,
|
|
string? Target,
|
|
IReadOnlyDictionary<string, JsonElement> Params,
|
|
string Schedule,
|
|
ParamValues Resolved);
|
|
|
|
/// <summary>
|
|
/// 有效任务集:线路任务模板 + 针对单个 Agent 的覆盖 + 该 Agent 的目标任务。
|
|
/// 参数经 ParamSpec 校验并补全默认值,Backend 和节点使用同一套规则。
|
|
/// </summary>
|
|
public static class EffectiveTasks
|
|
{
|
|
public const string LineScope = "line";
|
|
public const string TargetScope = "target";
|
|
|
|
public static IReadOnlyList<EffectiveTask> Compute(IReadOnlyList<TaskRecord> all, AgentRecord agent, bool filterByAgentKinds)
|
|
{
|
|
var result = new List<EffectiveTask>();
|
|
var overrides = new Dictionary<TaskId, TaskRecord>();
|
|
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<string, JsonElement> Merge(IReadOnlyDictionary<string, JsonElement> baseParams, IReadOnlyDictionary<string, JsonElement> over)
|
|
{
|
|
var merged = new Dictionary<string, JsonElement>(baseParams);
|
|
foreach ((string key, JsonElement value) in over)
|
|
{
|
|
merged[key] = value;
|
|
}
|
|
|
|
return merged;
|
|
}
|
|
|
|
private static void Add(
|
|
List<EffectiveTask> result,
|
|
TaskId id,
|
|
string scope,
|
|
string kind,
|
|
string? target,
|
|
IReadOnlyDictionary<string, JsonElement> 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));
|
|
}
|
|
|
|
/// <summary>该 Agent 持续线路任务的总带宽(bit/s)。</summary>
|
|
public static long ContinuousLineBudget(IReadOnlyList<EffectiveTask> 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;
|
|
}
|
|
}
|