Files
plezy/tvos/Runner/TvosEventDeliveryCoordinator.swift
edde746 09656fa4d3 fix(supply-chain): verify CI and production inputs
Pin external actions, images, toolchains, native archives, and tvOS engine artifacts; enforce fail-closed CI checks and keep website privacy disclosures aligned with shipped behavior.
2026-07-24 03:56:40 +02:00

106 lines
3.4 KiB
Swift

import Foundation
/// Keeps tvOS launcher events single-shot without suppressing a deliberate
/// second tap forever. All access is confined to the main thread by the host.
final class TvosDeepLinkDeliveryCoordinator {
struct Event: Equatable {
let contentId: String
let receivedAt: TimeInterval
var flutterArguments: [String: String] { ["contentId": contentId] }
fileprivate let sequence: UInt64
}
enum Receipt: Equatable {
case retained
case duplicate
case deliver(Event)
}
private let deduplicationWindow: TimeInterval
private let now: () -> TimeInterval
private var sequence: UInt64 = 0
private var liveDeliveryEnabled = false
private var pending: Event?
private var inFlight: Event?
private var lastDelivered: Event?
init(
deduplicationWindow: TimeInterval = 2,
now: @escaping () -> TimeInterval = { ProcessInfo.processInfo.systemUptime }
) {
precondition(deduplicationWindow >= 0)
self.deduplicationWindow = deduplicationWindow
self.now = now
}
/// A replacement Flutter engine must perform its initial read before live
/// delivery resumes. A launch event captured before registration is retained.
func bindEngine() {
liveDeliveryEnabled = false
inFlight = nil
}
func receive(contentId: String) -> Receipt {
let timestamp = now()
if let inFlight, isDuplicate(contentId: contentId, at: timestamp, of: inFlight) {
return .duplicate
}
if let pending, isDuplicate(contentId: contentId, at: timestamp, of: pending) {
// A retained failed delivery is retryable when no send is active.
return liveDeliveryEnabled && inFlight == nil ? beginDelivery(pending) : .duplicate
}
if let lastDelivered, isDuplicate(contentId: contentId, at: timestamp, of: lastDelivered) {
return .duplicate
}
sequence &+= 1
let event = Event(contentId: contentId, receivedAt: timestamp, sequence: sequence)
pending = event
guard liveDeliveryEnabled, inFlight == nil else { return .retained }
return beginDelivery(event)
}
/// Atomically transitions an engine from retained launch delivery to live
/// delivery and returns the one retained event, if any.
func beginLiveDelivery() -> Event? {
liveDeliveryEnabled = true
guard inFlight == nil, let pending else { return nil }
inFlight = pending
return pending
}
/// Clears a retained event only after Flutter reports successful delivery.
/// A newer retained event is returned so callers can deliver it next.
func complete(_ event: Event, succeeded: Bool) -> Event? {
guard inFlight == event else { return nil }
inFlight = nil
guard succeeded else { return nil }
lastDelivered = event
if pending == event {
pending = nil
}
guard liveDeliveryEnabled, let pending else { return nil }
return beginDelivery(pending).event
}
var retainedContentId: String? { pending?.contentId }
private func beginDelivery(_ event: Event) -> Receipt {
inFlight = event
return .deliver(event)
}
private func isDuplicate(contentId: String, at timestamp: TimeInterval, of event: Event) -> Bool {
contentId == event.contentId && timestamp - event.receivedAt <= deduplicationWindow
}
}
private extension TvosDeepLinkDeliveryCoordinator.Receipt {
var event: TvosDeepLinkDeliveryCoordinator.Event? {
if case let .deliver(event) = self { return event }
return nil
}
}