wake-ios/wake/Features/BlindBox/API/BlindBoxPolling.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()
}
}
}
}