TeraBackgroundUploadWaiter.swift (5698B)
1 import Foundation 2 import RadrootsKit 3 4 /// Exact retained-request discovery and cancellation-aware response waiting. 5 enum TeraBackgroundUploadWaiter { 6 static func matchingPersistedUpload( 7 transfer: any RadrootsBackgroundTransfer, 8 draftID: String, 9 expectedRevision: UInt64, 10 request: RadrootsBackgroundTransferRequest 11 ) async throws -> RadrootsBackgroundTransferSnapshot? { 12 try Task.checkCancellation() 13 let snapshots = try await transfer.snapshots() 14 let prefix = "radroots.add.\(draftID)." 15 let owned = snapshots.filter { $0.identifier.rawValue.hasPrefix(prefix) } 16 let parsed = try owned.map { snapshot in 17 guard let identity = TeraBackgroundUploadRequest.transferIdentity(snapshot.identifier), 18 identity.draftID == draftID, 19 identity.revision <= expectedRevision 20 else { 21 throw Self.failure( 22 code: "ios.add.background_upload_mismatch", 23 message: "The persisted photo upload identity is invalid." 24 ) 25 } 26 return snapshot 27 } 28 let candidates = parsed.filter { snapshot in 29 snapshot.state != .completed 30 || TeraBackgroundUploadRequest.persistedRequestMatches(snapshot.request, request: request) 31 } 32 try Task.checkCancellation() 33 let active = candidates.filter { $0.state != .completed } 34 guard active.count <= 1 else { 35 throw Self.failure( 36 code: "ios.add.background_upload_ambiguous", 37 message: "The persisted photo upload state is ambiguous." 38 ) 39 } 40 if let candidate = active.first { 41 guard TeraBackgroundUploadRequest.persistedRequestMatches(candidate.request, request: request) else { 42 throw Self.failure( 43 code: "ios.add.background_upload_mismatch", 44 message: "The persisted photo upload does not match the authorized upload." 45 ) 46 } 47 return candidate 48 } 49 let completed = candidates.filter { 50 $0.state == .completed && TeraBackgroundUploadRequest.persistedRequestMatches($0.request, request: request) 51 } 52 guard completed.count <= 1 else { 53 throw Self.failure( 54 code: "ios.add.background_upload_ambiguous", 55 message: "The persisted photo upload state is ambiguous." 56 ) 57 } 58 return completed.first 59 } 60 61 static func receipt( 62 transfer: any RadrootsBackgroundTransfer, 63 for identifier: RadrootsBackgroundTransferIdentifier, 64 draftID: String, 65 expectedRevision: UInt64, 66 request: RadrootsBackgroundTransferRequest, 67 baseline: RadrootsBackgroundTransferSnapshot? = nil, 68 waitNanoseconds: UInt64 = TeraRuntimeDeadlinePolicy.production.operationNanoseconds 69 ) async throws -> TeraAddBackgroundUploadReceipt { 70 guard waitNanoseconds > 0, waitNanoseconds <= TeraRuntimeDeadlinePolicy.production.operationNanoseconds, 71 let identity = TeraBackgroundUploadRequest.transferIdentity(identifier), 72 identity.draftID == draftID, identity.revision <= expectedRevision 73 else { throw TeraNativeUploadExecution.unknown } 74 let clock = ContinuousClock() 75 let deadline = clock.now.advanced(by: .nanoseconds(Int64(waitNanoseconds))) 76 var observed = baseline 77 while true { 78 try Task.checkCancellation() 79 guard clock.now < deadline else { throw TeraNativeUploadExecution.unknown } 80 guard let snapshot = try await transfer.snapshot(for: identifier) else { 81 throw failure( 82 code: "ios.add.background_upload_missing", 83 message: "The background photo upload could not be recovered." 84 ) 85 } 86 try Task.checkCancellation() 87 guard clock.now < deadline else { throw TeraNativeUploadExecution.unknown } 88 guard snapshot.identifier == identifier, 89 TeraBackgroundUploadRequest.persistedRequestMatches(snapshot.request, request: request), 90 observed == nil || observed?.executionID == snapshot.executionID 91 else { 92 throw Self.failure( 93 code: "ios.add.background_upload_mismatch", 94 message: "The persisted photo upload no longer matches its request." 95 ) 96 } 97 observed = snapshot 98 switch snapshot.state { 99 case .awaitingVerification, .completed: 100 try Task.checkCancellation() 101 return try completedReceipt(snapshot, identity: identity) 102 case .failed, .interrupted, .cancelled, .expired: 103 throw Self.failure( 104 code: snapshot.failure?.rawValue ?? "ios.add.background_upload_failed", 105 message: TeraUserMessages.text(.backgroundTransferFailed) 106 ) 107 case .queued, .running: 108 try await clock.sleep(until: min(deadline, clock.now.advanced(by: .milliseconds(100)))) 109 } 110 } 111 } 112 113 private static func completedReceipt(_ snapshot: RadrootsBackgroundTransferSnapshot, 114 identity: TeraNativeTransferIdentity) throws -> TeraAddBackgroundUploadReceipt 115 { 116 guard let response = snapshot.response, 117 let statusCode = UInt16(exactly: response.statusCode), let body = response.body 118 else { 119 throw failure(code: "ios.add.background_response_invalid", 120 message: "The photo service returned an invalid response.") 121 } 122 return TeraAddBackgroundUploadReceipt(identifier: snapshot.identifier.rawValue, 123 draftID: identity.draftID, expectedRevision: identity.revision, 124 statusCode: statusCode, mediaType: response.mediaType, 125 contentEncoding: response.contentEncoding, body: body) 126 } 127 128 private static func failure(code: String, message: String) -> TeraRuntimeFailure { 129 .local(operation: "add.media.background", code: code, safeMessage: message) 130 } 131 }