RadrootsBackgroundTaskQuery.swift (3154B)
1 import Foundation 2 3 /// A failed local OS inventory is unknown, never an empty successful inventory. 4 enum RadrootsBackgroundTaskQuery { 5 static let maximumTasks = 4096 6 static func read<Value: Sendable>( 7 timeoutNanoseconds: UInt64 = 5_000_000_000, 8 _ query: (@escaping @Sendable (Value) -> Void) -> Void 9 ) async throws -> Value { 10 guard timeoutNanoseconds > 0, timeoutNanoseconds <= 5_000_000_000 else { 11 throw RadrootsBackgroundTransferError.invalidRequest 12 } 13 let state = RadrootsBackgroundTaskQueryState<Value>() 14 let timer = Task { 15 do { try await Task.sleep(nanoseconds: timeoutNanoseconds) } catch { return } 16 state.resolve(.failure(.transferFailure)) 17 } 18 defer { timer.cancel() } 19 return try await withTaskCancellationHandler { 20 try await withCheckedThrowingContinuation { continuation in 21 guard state.install(continuation) else { return } 22 query { [weak state] value in state?.resolve(.success(value)) } 23 } 24 } onCancel: { 25 state.resolve(.failure(.transferFailure)) 26 } 27 } 28 29 static func descriptors(_ descriptions: [String?]) throws -> [RadrootsBackgroundURLTaskDescriptor] { 30 // Bound local parsing while retaining large recovered inventories. Refusal 31 // preserves all tasks and receipts and grants no new enqueue authority. 32 guard descriptions.count <= maximumTasks else { throw RadrootsBackgroundTransferError.transferFailure } 33 return try descriptions.map { description in 34 guard let description, description.utf8.count <= 256, 35 let descriptor = RadrootsBackgroundURLTaskDescriptor(taskDescription: description) 36 else { throw RadrootsBackgroundTransferError.transferFailure } 37 return descriptor 38 } 39 } 40 } 41 42 /// The lock protects every field. Only the first result wins; foreign callbacks 43 /// and continuation resumption always execute after releasing the lock. 44 private final class RadrootsBackgroundTaskQueryState<Value: Sendable>: @unchecked Sendable { 45 private let lock = NSLock() 46 private var continuation: CheckedContinuation<Value, any Error>? 47 private var resolved = false 48 private var earlyResult: Result<Value, RadrootsBackgroundTransferError>? 49 50 func install(_ continuation: CheckedContinuation<Value, any Error>) -> Bool { 51 lock.lock() 52 if let earlyResult { 53 self.earlyResult = nil 54 lock.unlock() 55 continuation.resume(with: earlyResult.mapError { $0 as any Error }) 56 return false 57 } 58 self.continuation = continuation 59 lock.unlock() 60 return true 61 } 62 63 func resolve(_ result: Result<Value, RadrootsBackgroundTransferError>) { 64 lock.lock() 65 guard !resolved else { lock.unlock(); return } 66 resolved = true 67 let pending = continuation 68 continuation = nil 69 if pending == nil { 70 earlyResult = result 71 } 72 lock.unlock() 73 pending?.resume(with: result.mapError { $0 as any Error }) 74 } 75 }