field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

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 }