RadrootsAppleBackgroundTransferAdapters.swift (4815B)
1 import Foundation 2 3 public struct RadrootsAppleBackgroundTransferAdapters: Sendable { 4 /// System-managed background sessions cannot establish the required 5 /// redirect/connect guarantee. Keep their legacy recovery operational, 6 /// and route new public work through the host's shared foreground uploader. 7 public static func supportsNewEnqueue(for policy: RadrootsBackgroundTransferNetworkPolicy) -> Bool { 8 #if os(iOS) && targetEnvironment(simulator) 9 policy == .simulatorLoopbackHTTP 10 #else 11 false 12 #endif 13 } 14 15 public let now: @Sendable () -> Date 16 public let enqueue: @Sendable (RadrootsBackgroundTransferRequest, UUID) async throws -> Void 17 public let cancel: @Sendable (RadrootsBackgroundTransferIdentifier) async throws -> Void 18 public let activeTransferIdentifiers: @Sendable () async throws -> Set<RadrootsBackgroundTransferIdentifier> 19 public let handleBackgroundEvents: @Sendable (String, @escaping @Sendable () -> Void) async -> Void 20 21 public init( 22 now: @escaping @Sendable () -> Date = Date.init, 23 enqueue: @escaping @Sendable (RadrootsBackgroundTransferRequest, UUID) async throws -> Void, 24 cancel: @escaping @Sendable (RadrootsBackgroundTransferIdentifier) async throws -> Void, 25 activeTransferIdentifiers: 26 @escaping @Sendable () async throws -> Set<RadrootsBackgroundTransferIdentifier>, 27 handleBackgroundEvents: 28 @escaping @Sendable (String, @escaping @Sendable () -> Void) async -> Void 29 ) { 30 self.now = now 31 self.enqueue = enqueue 32 self.cancel = cancel 33 self.activeTransferIdentifiers = activeTransferIdentifiers 34 self.handleBackgroundEvents = handleBackgroundEvents 35 } 36 37 public static let unavailable = Self( 38 enqueue: { _, _ in 39 throw RadrootsBackgroundTransferError.unavailable 40 }, 41 cancel: { _ in 42 throw RadrootsBackgroundTransferError.unavailable 43 }, 44 activeTransferIdentifiers: { 45 throw RadrootsBackgroundTransferError.unavailable 46 }, handleBackgroundEvents: { _, completionHandler in completionHandler() } 47 ) 48 49 public static func live( 50 sessionIdentifier: String, store: any RadrootsBackgroundTransferStore, 51 fileResolver: any RadrootsBackgroundTransferFileResolver, 52 downloadStagingRoot: URL, now: @escaping @Sendable () -> Date = Date.init 53 ) throws -> Self { 54 #if os(iOS) 55 let normalizedSessionIdentifier = 56 try RadrootsBackgroundTransferValidation.normalizedIdentifier(sessionIdentifier) 57 let session = RadrootsAppleBackgroundURLSession( 58 identifier: normalizedSessionIdentifier, store: store, fileResolver: fileResolver, 59 downloadStagingRoot: downloadStagingRoot, 60 now: now 61 ) 62 #if targetEnvironment(simulator) 63 let simulatorSession = RadrootsAppleBackgroundURLSession( 64 identifier: normalizedSessionIdentifier, store: store, fileResolver: fileResolver, 65 downloadStagingRoot: downloadStagingRoot, 66 now: now, usesForegroundSession: true 67 ) 68 #endif 69 return Self( 70 now: now, 71 enqueue: { request, executionID in 72 guard Self.supportsNewEnqueue(for: request.networkPolicy) else { 73 throw RadrootsBackgroundTransferError.unavailable 74 } 75 #if targetEnvironment(simulator) 76 try await simulatorSession.enqueue(request, executionID: executionID) 77 #else 78 throw RadrootsBackgroundTransferError.unavailable 79 #endif 80 }, 81 cancel: { identifier in 82 #if targetEnvironment(simulator) 83 try await simulatorSession.cancel(identifier) 84 #endif 85 try await session.cancel(identifier) 86 }, 87 activeTransferIdentifiers: { 88 var identifiers = try await session.activeTransferIdentifiers() 89 #if targetEnvironment(simulator) 90 try await identifiers.formUnion(simulatorSession.activeTransferIdentifiers()) 91 #endif 92 return identifiers 93 }, 94 handleBackgroundEvents: { identifier, completionHandler in 95 await session.handleBackgroundEvents( 96 identifier: identifier, completionHandler: completionHandler 97 ) 98 } 99 ) 100 #else 101 return .unavailable 102 #endif 103 } 104 }