import type { DownloadStatus, PauseReason } from "@umt/contracts"; import type { DownloadTaskStatus as DomainDownloadStatus } from "@umt/domain"; // 下载状态:domain 只描述"下载器里看到的状态"(mapQbState 的结果), // contracts / download_task.status 还叠加业务阶段(submitting / stalled / importing / imported)和 pauseReason。 export type { DomainDownloadStatus }; export interface ContractDownloadState { status: DownloadStatus; pauseReason: PauseReason | null; } const TO_CONTRACT: Record = { queued: { status: "queued", pauseReason: null }, downloading: { status: "downloading", pauseReason: null }, paused_by_threshold: { status: "paused", pauseReason: "threshold" }, paused_by_user: { status: "paused", pauseReason: "user" }, completed: { status: "completed", pauseReason: null }, error: { status: "failed", pauseReason: null }, missing_files: { status: "missing", pauseReason: null }, removed: { status: "removed", pauseReason: null }, }; /** contracts 状态 → 下载器层面的 domain 状态(业务叠加态折回其底层下载状态) */ const TO_DOMAIN: Record = { queued: "queued", // 提交中:下载器里还没有/刚出现,按排队处理 submitting: "queued", downloading: "downloading", paused: "by_pause_reason", // 无进展是业务判定(detectNoProgress),下载器里仍是 downloading stalled: "downloading", completed: "completed", // 入库阶段:下载本身已完成 importing: "completed", imported: "completed", failed: "error", removed: "removed", missing: "missing_files", }; /** 暂停原因 → domain 状态:只有 threshold 会被阈值恢复自动恢复,其余都按用户暂停对待(REQ §8.4.1) */ const PAUSE_TO_DOMAIN: Record = { threshold: "paused_by_threshold", user: "paused_by_user", policy: "paused_by_user", agent: "paused_by_user", }; export const DOMAIN_DOWNLOAD_STATUSES = Object.keys(TO_CONTRACT) as DomainDownloadStatus[]; export function toContractDownloadState(s: DomainDownloadStatus): ContractDownloadState { return { ...TO_CONTRACT[s] }; } export function toDomainDownloadStatus(status: DownloadStatus, pauseReason: PauseReason | null): DomainDownloadStatus { const d = TO_DOMAIN[status]; if (d !== "by_pause_reason") return d; return PAUSE_TO_DOMAIN[pauseReason ?? "user"]; } /** * 同步轮询时合并"下载器观察"与"当前业务状态": * - 业务叠加态在其底层下载状态不变时保留(importing/imported 遇 completed、stalled 遇 downloading、submitting 遇 queued); * - 暂停原因为 policy/agent 且下载器仍是暂停时保留原因,不被改写成 user; * - 其余以观察为准。 */ export function mergeObservedDownloadState( current: ContractDownloadState, observed: DomainDownloadStatus, ): ContractDownloadState { const next = TO_CONTRACT[observed]; const keep = ((current.status === "importing" || current.status === "imported") && observed === "completed") || (current.status === "stalled" && observed === "downloading") || (current.status === "submitting" && observed === "queued"); if (keep) return { ...current }; if ( current.status === "paused" && observed === "paused_by_user" && (current.pauseReason === "policy" || current.pauseReason === "agent") ) { return { ...current }; } return { ...next }; }