TeraSubmissionStopControl.swift (1801B)
1 import Foundation 2 3 /// Cancels only this submission's native upload waiter. Durable operation and 4 /// OS transfer evidence remain owned by Rust and the background transfer store. 5 @MainActor 6 final class TeraSubmissionStopControl { 7 private(set) var requested = false 8 private var uploadWaiter: Task<TeraAddBackgroundUploadReceipt, Error>? 9 private var renewalWaiter: Task<TeraSubmissionStatus, Error>? 10 11 func request() { 12 requested = true 13 uploadWaiter?.cancel() 14 renewalWaiter?.cancel() 15 } 16 17 func reset() { 18 uploadWaiter?.cancel() 19 uploadWaiter = nil 20 renewalWaiter?.cancel() 21 renewalWaiter = nil 22 requested = false 23 } 24 25 func renew(using media: any TeraAddMediaHandling, submission: TeraSubmissionStatus, 26 source: TeraPreparedMedia, client: TeraRuntimeClient) async throws -> TeraSubmissionStatus 27 { 28 guard !requested, uploadWaiter == nil, renewalWaiter == nil else { throw CancellationError() } 29 let task = Task { try await media.renewSubmissionUpload(submission, media: source, client: client) } 30 renewalWaiter = task 31 defer { renewalWaiter = nil } 32 return try await withTaskCancellationHandler { try await task.value } onCancel: { task.cancel() } 33 } 34 35 func upload(using media: any TeraAddMediaHandling, transfer: TeraNativeTransferJob, 36 source: TeraPreparedMedia) async throws -> TeraAddBackgroundUploadReceipt 37 { 38 guard !requested, uploadWaiter == nil else { throw CancellationError() } 39 let task = Task { 40 try Task.checkCancellation() 41 return try await media.uploadInBackground(transfer: transfer, media: source) 42 } 43 uploadWaiter = task 44 defer { uploadWaiter = nil } 45 return try await withTaskCancellationHandler { 46 try await task.value 47 } onCancel: { 48 task.cancel() 49 } 50 } 51 }