using System.Text.Json; using System.Text.Json.Serialization; using w4c_workflows.Models; namespace w4c_workflows.Services.Triggers; /// /// Typed trigger model parsed from Workflow.TriggerJson. 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 and the type is guaranteed non-null. /// 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, }; /// /// Parses stored trigger JSON. Returns null (with a non-null /// ) when the JSON is absent, malformed, or the /// trigger lacks a valid type/interval. /// public static TriggerSpec? Parse(string? json, out string? error) { error = null; if (string.IsNullOrWhiteSpace(json)) return null; TriggerDefinition def; try { def = JsonSerializer.Deserialize(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); } }