import type { BackupJobStatusResponse, CreateBackupRequest } from "@mmapp/contracts/backups" import { getBackupJob } from "@/shared/api/backups" export function waitForBackupPoll(ms: number, signal: AbortSignal): Promise { return new Promise((resolve, reject) => { if (signal.aborted) { reject(signal.reason); return } const abort = () => { clearTimeout(timer); signal.removeEventListener("abort", abort); reject(signal.reason) } const timer = setTimeout(() => { signal.removeEventListener("abort", abort); resolve() }, ms) signal.addEventListener("abort", abort, { once: true }) }) } export async function pollBackupJob(baseUrl: string, jobId: string, target: CreateBackupRequest, options: { signal: AbortSignal; onJob?: (job: BackupJobStatusResponse) => void; readJob?: typeof getBackupJob; wait?: typeof waitForBackupPoll; attempts?: number; intervalMs?: number }) { const signal = AbortSignal.any([options.signal, AbortSignal.timeout(300_000)]) const readJob = options.readJob ?? getBackupJob, wait = options.wait ?? waitForBackupPoll, attempts = options.attempts ?? 150 for (let index = 0; index < attempts; index++) { signal.throwIfAborted() const job = await readJob(baseUrl, jobId, { signal }); signal.throwIfAborted() if (job.id !== jobId || JSON.stringify(job.serverIds) !== JSON.stringify(target.serverIds.map(String)) || (job.notes ?? "") !== (target.notes?.trim() ?? "")) throw new Error("Ответ задачи не соответствует выбранным серверам или заметке") options.onJob?.(job) if (job.status === "done" || job.status === "failed") return job if (index + 1 < attempts) await wait(options.intervalMs ?? 1200, signal) } throw new Error("Время наблюдения истекло. Задача может продолжаться; повторите проверку той же задачи") } export function backupJobOutcome(job: BackupJobStatusResponse) { const uploadFailures = job.created.filter(item => item.uploadError) return { fullSuccess: job.status === "done" && job.created.length === job.total && !job.failures.length && !uploadFailures.length, created: job.created.length, deviceFailures: job.failures, uploadFailures } }