summaryrefslogtreecommitdiff
path: root/src/SomhairlesDream.Shared/Domain.fs
diff options
context:
space:
mode:
Diffstat (limited to 'src/SomhairlesDream.Shared/Domain.fs')
-rw-r--r--src/SomhairlesDream.Shared/Domain.fs102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/SomhairlesDream.Shared/Domain.fs b/src/SomhairlesDream.Shared/Domain.fs
new file mode 100644
index 0000000..fd229fa
--- /dev/null
+++ b/src/SomhairlesDream.Shared/Domain.fs
@@ -0,0 +1,102 @@
+namespace SomhairlesDream.Shared
+
+open System
+
+[<RequireQualifiedAccess>]
+type RunStatus =
+ | Idle = 0
+ | Queued = 1
+ | Running = 2
+ | Succeeded = 3
+ | Failed = 4
+ | Stale = 5
+
+type Vector3 =
+ { X: float
+ Y: float
+ Z: float }
+
+type MeshSnapshot =
+ { Version: int
+ Label: string
+ Vertices: Vector3 array
+ Faces: int array array }
+
+type LiveSnapshot =
+ { ProjectId: string
+ RunId: string
+ Status: RunStatus
+ CurrentVersion: int
+ TargetVersion: int
+ HeartbeatAt: DateTimeOffset option
+ UpdatedAt: DateTimeOffset
+ Message: string
+ Mesh: MeshSnapshot option
+ NextDesignRunScheduled: bool }
+
+module MeshData =
+ let positionData (mesh: MeshSnapshot) =
+ mesh.Vertices
+ |> Array.collect (fun vertex -> [| vertex.X; vertex.Y; vertex.Z |])
+
+ let triangleIndices (mesh: MeshSnapshot) =
+ mesh.Faces
+ |> Array.collect (fun face ->
+ if face.Length < 3 then
+ [||]
+ else
+ [| for index in 1 .. face.Length - 2 do
+ yield face[0]
+ yield face[index]
+ yield face[index + 1] |])
+
+module RunState =
+ let initial projectId runId now =
+ { ProjectId = projectId
+ RunId = runId
+ Status = RunStatus.Idle
+ CurrentVersion = 0
+ TargetVersion = 0
+ HeartbeatAt = None
+ UpdatedAt = now
+ Message = "等待设计运行"
+ Mesh = None
+ NextDesignRunScheduled = false }
+
+ let start now state =
+ let targetVersion = state.TargetVersion + 1
+
+ { state with
+ Status = RunStatus.Running
+ TargetVersion = targetVersion
+ HeartbeatAt = Some now
+ UpdatedAt = now
+ Message = $"正在生成第 {targetVersion} 版几何"
+ NextDesignRunScheduled = false }
+
+ let heartbeat now state =
+ if state.Status = RunStatus.Running then
+ { state with
+ HeartbeatAt = Some now
+ UpdatedAt = now }
+ else
+ state
+
+ let statusAt timeout now state =
+ match state.HeartbeatAt with
+ | Some heartbeatAt when state.Status = RunStatus.Running && now - heartbeatAt > timeout ->
+ { state with
+ Status = RunStatus.Stale
+ UpdatedAt = now
+ Message = "心跳超时,等待重连" }
+ | _ -> state
+
+ let publish now mesh state =
+ { state with
+ Status = RunStatus.Succeeded
+ CurrentVersion = mesh.Version
+ HeartbeatAt = Some now
+ UpdatedAt = now
+ Message = $"已发布{mesh.Label}"
+ Mesh = Some mesh
+ NextDesignRunScheduled = false }