RadrootsBackgroundURLTaskDescriptor.swift (4105B)
1 import Foundation 2 3 enum RadrootsStagedBackgroundDownloadResult: Sendable, Equatable { 4 case file(URL) 5 case failure 6 } 7 8 struct RadrootsBackgroundHTTPResult: Sendable, Equatable { 9 let statusCode: Int? 10 let mediaType: String? 11 let body: Data? 12 let contentEncoding: String? 13 let bodyExceeded: Bool 14 let mediaTypeWasMalformed: Bool 15 let destinationMismatch: Bool 16 let headerFailure: RadrootsBackgroundTransferFailure? 17 18 init( 19 statusCode: Int?, mediaType: String?, body: Data?, contentEncoding: String? = nil, 20 bodyExceeded: Bool, 21 mediaTypeWasMalformed: Bool = false, destinationMismatch: Bool = false, 22 headerFailure: RadrootsBackgroundTransferFailure? = nil 23 ) { 24 self.statusCode = statusCode 25 self.mediaType = mediaType 26 self.body = body 27 self.contentEncoding = contentEncoding 28 self.bodyExceeded = bodyExceeded 29 self.mediaTypeWasMalformed = mediaTypeWasMalformed 30 self.destinationMismatch = destinationMismatch 31 self.headerFailure = headerFailure 32 } 33 } 34 35 struct RadrootsBackgroundURLTaskDescriptor: Sendable, Equatable { 36 private static let prefix = "radroots-transfer-v1" 37 38 let identifier: RadrootsBackgroundTransferIdentifier 39 let maximumTransferBytes: UInt64 40 let maximumResponseBodyBytes: Int 41 let executionID: UUID? 42 43 init(request: RadrootsBackgroundTransferRequest, executionID: UUID? = nil) { 44 identifier = request.identifier 45 maximumTransferBytes = request.maximumTransferBytes 46 maximumResponseBodyBytes = request.responsePolicy.maximumBodyBytes 47 self.executionID = executionID 48 } 49 50 init?(taskDescription: String?) { 51 guard let taskDescription else { return nil } 52 let components = taskDescription.split(separator: "|", omittingEmptySubsequences: false) 53 if components.count == 5, components[0] == "radroots-transfer-v2", 54 let executionID = UUID(uuidString: String(components[4])), 55 let previous = Self(taskDescription: ([Self.prefix] + components[1 ... 3].map(String.init)) 56 .joined(separator: "|")) { 57 identifier = previous.identifier 58 maximumTransferBytes = previous.maximumTransferBytes 59 maximumResponseBodyBytes = previous.maximumResponseBodyBytes 60 self.executionID = executionID 61 return 62 } 63 if components.count == 4, 64 components[0] == Substring(Self.prefix), 65 let identifier = try? RadrootsBackgroundTransferIdentifier(String(components[1])), 66 let maximumTransferBytes = UInt64(components[2]), 67 let maximumResponseBodyBytes = Int(components[3]), 68 maximumTransferBytes > 0, 69 maximumTransferBytes <= RadrootsBackgroundTransferRequest.absoluteMaximumTransferBytes, 70 (0 ... 65536).contains(maximumResponseBodyBytes) { 71 self.identifier = identifier 72 self.maximumTransferBytes = maximumTransferBytes 73 self.maximumResponseBodyBytes = maximumResponseBodyBytes 74 executionID = nil 75 return 76 } 77 guard let legacyIdentifier = try? RadrootsBackgroundTransferIdentifier(taskDescription) else { 78 return nil 79 } 80 identifier = legacyIdentifier 81 maximumTransferBytes = RadrootsBackgroundTransferRequest.defaultMaximumTransferBytes 82 maximumResponseBodyBytes = 65536 83 executionID = nil 84 } 85 86 var taskDescription: String { 87 if let executionID { 88 return "radroots-transfer-v2|\(identifier.rawValue)|\(maximumTransferBytes)|" 89 + "\(maximumResponseBodyBytes)|\(executionID.uuidString.lowercased())" 90 } 91 return "\(Self.prefix)|\(identifier.rawValue)|\(maximumTransferBytes)|\(maximumResponseBodyBytes)" 92 } 93 } 94 95 extension RadrootsBackgroundTransferRequest { 96 var isUpload: Bool { 97 if case .upload = operation { 98 return true 99 } 100 return false 101 } 102 } 103 104 struct RadrootsTransferResponseError: Error { 105 let failure: RadrootsBackgroundTransferFailure 106 }