w4c-workflows-api/Services/Triggers/TriggerSpec.cs

67 lines
2 KiB
C#

using System.Text.Json;
using System.Text.Json.Serialization;
using w4c_workflows.Models;
namespace w4c_workflows.Services.Triggers;
/// <summary>
/// Typed trigger model parsed from <c>Workflow.TriggerJson</c>. The compiler
/// stores the trigger exactly as it appeared in YAML (camelCase, nulls omitted);
/// this record normalizes it for the trigger engine: the interval string becomes
/// a parsed <see cref="TimeSpan"/> and the type is guaranteed non-null.
/// </summary>
public sealed record TriggerSpec(
string Type,
string? Cron,
TimeSpan? Interval,
string? WebhookPath,
string? Stream)
{
private static readonly JsonSerializerOptions Json = new(JsonSerializerDefaults.Web)
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
};
/// <summary>
/// Parses stored trigger JSON. Returns null (with a non-null
/// <paramref name="error"/>) when the JSON is absent, malformed, or the
/// trigger lacks a valid type/interval.
/// </summary>
public static TriggerSpec? Parse(string? json, out string? error)
{
error = null;
if (string.IsNullOrWhiteSpace(json))
return null;
TriggerDefinition def;
try
{
def = JsonSerializer.Deserialize<TriggerDefinition>(json, Json) ?? new TriggerDefinition();
}
catch (JsonException ex)
{
error = ex.Message;
return null;
}
if (string.IsNullOrWhiteSpace(def.Type))
{
error = "trigger.type is missing";
return null;
}
TimeSpan? interval = null;
if (!string.IsNullOrWhiteSpace(def.Interval))
{
if (!DurationParser.TryParse(def.Interval, out var parsed))
{
error = $"trigger.interval '{def.Interval}' is not a valid duration";
return null;
}
interval = parsed;
}
return new TriggerSpec(def.Type, def.Cron, interval, def.WebhookPath, def.Stream);
}
}