TeraStoppedUploadRecovery.swift (2259B)
1 import Foundation 2 import RadrootsKit 3 4 /// Reads only an already-owned native response. Never enqueues or retries work. 5 enum TeraStoppedUploadRecovery { 6 static func receipt(_ submission: TeraSubmissionStatus, media: TeraPreparedMedia, 7 transfer: any RadrootsBackgroundTransfer) async throws -> TeraAddBackgroundUploadReceipt? 8 { 9 guard submission.delivery.isStopped, 10 let item = submission.media.first(where: { $0.opaqueReference == media.opaqueReference }), 11 item.progress.stage == .uploading else { throw TeraComposerAcknowledgment.unconfirmed } 12 let snapshots = try await transfer.snapshots() 13 try Task.checkCancellation() 14 let candidates = try snapshots.filter { snapshot in 15 guard snapshot.identifier.rawValue.hasPrefix("radroots.add.\(submission.intentID).") else { return false } 16 guard let identity = TeraBackgroundUploadRequest.transferIdentity(snapshot.identifier), 17 identity.draftID == submission.intentID, identity.revision <= submission.revision 18 else { throw TeraComposerAcknowledgment.unconfirmed } 19 guard snapshot.request.expectedSourceSHA256 == media.sha256 else { return false } 20 guard try TeraBackgroundUploadRequest.persistedRequestMatchesMedia( 21 snapshot.request, media: media, uploadURL: item.progress.uploadURL 22 ) else { throw TeraComposerAcknowledgment.unconfirmed } 23 return true 24 } 25 guard candidates.count <= 1 else { throw TeraComposerAcknowledgment.unconfirmed } 26 guard let snapshot = candidates.first, 27 let identity = TeraBackgroundUploadRequest.transferIdentity(snapshot.identifier), 28 [.awaitingVerification, .completed].contains(snapshot.state) else { return nil } 29 guard let response = snapshot.response, let status = UInt16(exactly: response.statusCode), 30 let body = response.body else { throw TeraComposerAcknowledgment.unconfirmed } 31 return TeraAddBackgroundUploadReceipt(identifier: snapshot.identifier.rawValue, draftID: submission.intentID, 32 expectedRevision: identity.revision, statusCode: status, 33 mediaType: response.mediaType, contentEncoding: response.contentEncoding, body: body) 34 } 35 }