188 lines · 7.0 KB · Swift
RawDownload
#if os(macOS)import Foundation extension OpenAIDashboardBrowserCookieImporter {    private struct PendingCookieStoreMutation {        let token: UUID        let task: Task<Void, Never>    }     @MainActor private static var pendingCookieStoreMutations: [ObjectIdentifier: PendingCookieStoreMutation] = [:]    private nonisolated static let cookieCacheQueue = DispatchQueue(        label: "com.steipete.codexbar.openai-cookie-cache")    private nonisolated static let deadlineQueue = DispatchQueue(        label: "com.steipete.codexbar.openai-cookie-deadline",        qos: .userInitiated)     private final class CookieLoadCompletion: @unchecked Sendable {        private let lock = NSLock()        private var didFinish = false         func finish(_ action: () -> Void) {            let shouldFinish = self.lock.withLock {                guard !self.didFinish else { return false }                self.didFinish = true                return true            }            if shouldFinish { action() }        }    }     nonisolated static func remainingTimeout(        until deadline: Date?,        cappedAt localLimit: TimeInterval? = nil,        now: Date = Date()) throws -> TimeInterval    {        guard let deadline else {            return localLimit.map(OpenAIDashboardFetcher.sanitizedTimeout) ?? .greatestFiniteMagnitude        }        let remaining = deadline.timeIntervalSince(now)        guard remaining > 0 else { throw URLError(.timedOut) }        guard let localLimit else { return remaining }        return min(OpenAIDashboardFetcher.sanitizedTimeout(localLimit), remaining)    }     nonisolated static func runBoundedCookieLoad<T: Sendable>(        deadline: Date?,        timeoutObserver: (@Sendable () -> Void)? = nil,        operation: @escaping @Sendable () throws -> T) async throws -> T    {        guard let deadline else {            return try await Task.detached(priority: .userInitiated, operation: operation).value        }        let timeout = try self.remainingTimeout(until: deadline)        let completion = CookieLoadCompletion()        return try await withCheckedThrowingContinuation { continuation in            DispatchQueue.global(qos: .userInitiated).async {                let result = Result(catching: operation)                completion.finish { continuation.resume(with: result) }            }            self.deadlineQueue.asyncAfter(deadline: .now() + timeout) {                completion.finish {                    timeoutObserver?()                    continuation.resume(throwing: URLError(.timedOut))                }            }        }    }     nonisolated static func runBoundedCookieCacheOperation<T: Sendable>(        deadline: Date?,        operation: @escaping @Sendable () throws -> T) async throws -> T    {        guard let deadline else {            return try await withCheckedThrowingContinuation { continuation in                self.cookieCacheQueue.async {                    continuation.resume(with: Result(catching: operation))                }            }        }         let timeout = try self.remainingTimeout(until: deadline)        let completion = CookieLoadCompletion()        return try await withCheckedThrowingContinuation { continuation in            self.cookieCacheQueue.async {                let result = Result(catching: operation)                completion.finish { continuation.resume(with: result) }            }            self.deadlineQueue.asyncAfter(deadline: .now() + timeout) {                completion.finish { continuation.resume(throwing: URLError(.timedOut)) }            }        }    }     static func runBoundedCallback(        deadline: Date?,        timeoutObserver: (@Sendable () -> Void)? = nil,        start: (@escaping @Sendable () -> Void) -> Void) async throws    {        let completion = CookieLoadCompletion()        guard let deadline else {            await withCheckedContinuation { continuation in                start {                    completion.finish { continuation.resume() }                }            }            return        }         let timeout = try self.remainingTimeout(until: deadline)        try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in            start {                completion.finish { continuation.resume() }            }            self.deadlineQueue.asyncAfter(deadline: .now() + timeout) {                completion.finish {                    timeoutObserver?()                    continuation.resume(throwing: URLError(.timedOut))                }            }        }    }     static func runBoundedValueCallback<T: Sendable>(        deadline: Date?,        timeoutObserver: (@Sendable () -> Void)? = nil,        start: (@escaping @Sendable (T) -> Void) -> Void) async throws -> T    {        let completion = CookieLoadCompletion()        guard let deadline else {            return await withCheckedContinuation { continuation in                start { value in                    completion.finish { continuation.resume(returning: value) }                }            }        }         let timeout = try self.remainingTimeout(until: deadline)        return try await withCheckedThrowingContinuation { continuation in            start { value in                completion.finish { continuation.resume(returning: value) }            }            self.deadlineQueue.asyncAfter(deadline: .now() + timeout) {                completion.finish {                    timeoutObserver?()                    continuation.resume(throwing: URLError(.timedOut))                }            }        }    }     static func runSerializedCallback(        key: ObjectIdentifier,        deadline: Date?,        start: @escaping (@escaping @Sendable () -> Void) -> Void) async throws    {        while let pending = self.pendingCookieStoreMutations[key] {            try await self.waitForMutation(pending.task, deadline: deadline)            if self.pendingCookieStoreMutations[key]?.token == pending.token {                self.pendingCookieStoreMutations[key] = nil            }        }         let token = UUID()        let task = Task { @MainActor in            await withCheckedContinuation { continuation in                start { continuation.resume() }            }        }        self.pendingCookieStoreMutations[key] = PendingCookieStoreMutation(token: token, task: task)        Task { @MainActor in            await task.value            if self.pendingCookieStoreMutations[key]?.token == token {                self.pendingCookieStoreMutations[key] = nil            }        }        try await self.waitForMutation(task, deadline: deadline)    }     private static func waitForMutation(_ task: Task<Void, Never>, deadline: Date?) async throws {        try await self.runBoundedCallback(deadline: deadline) { completion in            Task { @MainActor in                await task.value                completion()            }        }    }}#endif