namespace SomhairlesDream.Shared open System #if !FABLE_COMPILER open System.Text.Json open System.Text.Json.Nodes #endif [] type RunIds = { ProjectId: string RunId: string BaseId: string TargetId: string } module Ids = open System.Text.RegularExpressions let private resourcePattern = Regex("^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$", RegexOptions.CultureInvariant) let private objectPattern = Regex("^[a-z0-9]+(?:[._-][a-z0-9]+)*$", RegexOptions.CultureInvariant) let validateResourceId value = if isNull value || not (resourcePattern.IsMatch(value)) then Error "resource id must contain only lower-case letters, digits, and hyphens" else Ok () let validateObjectId value = if isNull value || not (objectPattern.IsMatch(value)) then Error "object id must use the dotted lower-case namespace" else Ok () [] type RunStart = { Ids: RunIds At: DateTimeOffset TotalSteps: int } [] type RunHeartbeat = { Ids: RunIds At: DateTimeOffset Message: string } [] type RunCheckpoint = { Ids: RunIds At: DateTimeOffset StepId: string StepIndex: int TotalSteps: int Message: string ArtifactPath: string } [] type RunComplete = { Ids: RunIds At: DateTimeOffset ManifestPath: string } [] type RunFail = { Ids: RunIds At: DateTimeOffset StepId: string option Message: string } type RunEvent = | Start of RunStart | Heartbeat of RunHeartbeat | Checkpoint of RunCheckpoint | Complete of RunComplete | Fail of RunFail [] type RunEventWire = { Kind: string At: DateTimeOffset ProjectId: string RunId: string BaseId: string TargetId: string TotalSteps: int option StepId: string option StepIndex: int option Message: string option ArtifactPath: string option ManifestPath: string option } module RunEvent = let private ids (value: RunIds) = value.ProjectId, value.RunId, value.BaseId, value.TargetId let toWire event = let kind, eventIds, at, totalSteps, stepId, stepIndex, message, artifactPath, manifestPath = match event with | Start value -> "start", value.Ids, value.At, Some value.TotalSteps, None, None, None, None, None | Heartbeat value -> "heartbeat", value.Ids, value.At, None, None, None, Some value.Message, None, None | Checkpoint value -> "checkpoint", value.Ids, value.At, Some value.TotalSteps, Some value.StepId, Some value.StepIndex, Some value.Message, Some value.ArtifactPath, None | Complete value -> "complete", value.Ids, value.At, None, None, None, None, None, Some value.ManifestPath | Fail value -> "fail", value.Ids, value.At, None, value.StepId, None, Some value.Message, None, None let projectId, runId, baseId, targetId = ids eventIds { Kind = kind At = at ProjectId = projectId RunId = runId BaseId = baseId TargetId = targetId TotalSteps = totalSteps StepId = stepId StepIndex = stepIndex Message = message ArtifactPath = artifactPath ManifestPath = manifestPath } #if !FABLE_COMPILER let private addOptional (json: JsonObject) (name: string) value create = match value with | Some item -> json[name] <- create item | None -> () let private jsonOptions () = let options = JsonSerializerOptions() options.PropertyNamingPolicy <- JsonNamingPolicy.CamelCase options.WriteIndented <- false options let toJson event = let wire = toWire event let json = JsonObject() json["kind"] <- JsonValue.Create(wire.Kind) json["at"] <- JsonValue.Create(wire.At) json["projectId"] <- JsonValue.Create(wire.ProjectId) json["runId"] <- JsonValue.Create(wire.RunId) json["baseId"] <- JsonValue.Create(wire.BaseId) json["targetId"] <- JsonValue.Create(wire.TargetId) addOptional json "totalSteps" wire.TotalSteps (fun value -> JsonValue.Create(value)) addOptional json "stepId" wire.StepId (fun value -> JsonValue.Create(value)) addOptional json "stepIndex" wire.StepIndex (fun value -> JsonValue.Create(value)) addOptional json "message" wire.Message (fun value -> JsonValue.Create(value)) addOptional json "artifactPath" wire.ArtifactPath (fun value -> JsonValue.Create(value)) addOptional json "manifestPath" wire.ManifestPath (fun value -> JsonValue.Create(value)) json.ToJsonString(jsonOptions()) #endif [] type ArtifactChange = { ObjectId: string Kind: string Summary: string } [] type RenderArtifact = { ArtifactPath: string Sha256: string Bytes: int64 ExportedAt: DateTimeOffset } [] type StepArtifact = { StepId: string StepIndex: int ArtifactPath: string LogPath: string Sha256: string Bytes: int64 ExportedAt: DateTimeOffset ObjectIds: string array VerifiedObjectIds: string array Changes: ArtifactChange array Render: RenderArtifact option } [] type ArtifactManifest = { SchemaVersion: int ProjectId: string RunId: string BaseId: string TargetId: string Status: string StartedAt: DateTimeOffset CompletedAt: DateTimeOffset BlenderVersion: string Steps: StepArtifact array } [] type RunSnapshot = { ProjectId: string RunId: string BaseId: string TargetId: string Status: string CurrentStepId: string option CurrentStepIndex: int TotalSteps: int CompletedSteps: string array LastHeartbeatAt: DateTimeOffset option UpdatedAt: DateTimeOffset Message: string ManifestPath: string option ManifestUrl: string option Error: string option IsStale: bool }