66 lines
2.6 KiB
Swift
66 lines
2.6 KiB
Swift
import Foundation
|
|
|
|
// MARK: - BlindBox Async Polling Sequences
|
|
|
|
enum BlindBoxPolling {
|
|
/// Poll a single blind box until it becomes "Unopened".
|
|
/// Yields once when ready, then finishes.
|
|
static func singleBox(boxId: String, intervalSeconds: Double = 2.0) -> AsyncThrowingStream<BlindBoxData, Error> {
|
|
AsyncThrowingStream { continuation in
|
|
let task = Task {
|
|
while !Task.isCancelled {
|
|
do {
|
|
let result = try await BlindBoxApi.shared.getBlindBox(boxId: boxId)
|
|
if let data = result {
|
|
if data.status.lowercased() == "unopened" {
|
|
continuation.yield(data)
|
|
continuation.finish()
|
|
break
|
|
}
|
|
}
|
|
try await Task.sleep(nanoseconds: UInt64(intervalSeconds * 1_000_000_000))
|
|
} catch is CancellationError {
|
|
continuation.finish()
|
|
break
|
|
} catch {
|
|
continuation.finish(throwing: error)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
continuation.onTermination = { @Sendable _ in
|
|
task.cancel()
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Poll blind box list and yield first unopened box when available.
|
|
/// Yields once when found, then finishes.
|
|
static func firstUnopened(intervalSeconds: Double = 2.0) -> AsyncThrowingStream<BlindBoxData, Error> {
|
|
AsyncThrowingStream { continuation in
|
|
let task = Task {
|
|
while !Task.isCancelled {
|
|
do {
|
|
let list = try await BlindBoxApi.shared.getBlindBoxList()
|
|
if let item = list?.first(where: { $0.status.lowercased() == "unopened" }) {
|
|
continuation.yield(item)
|
|
continuation.finish()
|
|
break
|
|
}
|
|
try await Task.sleep(nanoseconds: UInt64(intervalSeconds * 1_000_000_000))
|
|
} catch is CancellationError {
|
|
continuation.finish()
|
|
break
|
|
} catch {
|
|
continuation.finish(throwing: error)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
continuation.onTermination = { @Sendable _ in
|
|
task.cancel()
|
|
}
|
|
}
|
|
}
|
|
}
|