import Foundation actor SDLSuperService { typealias MessageHandler = @Sendable (SDLQUICInboundMessage) async -> Void private let serverEndpoint: SDLConfiguration.ResolvedServerEndpoint private let port: UInt16 private let onMessage: MessageHandler private var superClient: SDLSuperClient? private var monitorTask: Task? init(serverEndpoint: SDLConfiguration.ResolvedServerEndpoint, port: UInt16 = 1443, onMessage: @escaping MessageHandler) { self.serverEndpoint = serverEndpoint self.port = port self.onMessage = onMessage } func start() { guard self.monitorTask == nil else { return } self.monitorTask = startMonitorTask(name: "superServiceMonitor") { [weak self] in guard let self else { throw CancellationError() } try await self.runOnce() } } func stop() async { let monitorTask = self.monitorTask self.monitorTask = nil let superClient = self.superClient self.superClient = nil monitorTask?.cancel() await superClient?.stop() if let monitorTask { await monitorTask.value } } func send(type: SDLPacketType, data: Data) async { await self.superClient?.send(type: type, data: data) } private func runOnce() async throws { let superClient = SDLSuperClient(serverEndpoint: self.serverEndpoint, port: self.port) self.superClient = superClient await superClient.start() do { try await withTaskCancellationHandler { try await self.run(superClient) } onCancel: { Task { await superClient.stop() } } await self.cleanup(superClient) } catch { await self.cleanup(superClient) throw error } } private func run(_ superClient: SDLSuperClient) async throws { try await Task.sleep(for: .seconds(0.5)) try Task.checkCancellation() SDLLogger.log("[SDLSuperService] start super client: \(self.serverEndpoint.ip)") try await withThrowingTaskGroup(of: Void.self) { group in defer { group.cancelAll() } let onMessage = self.onMessage group.addTask { for try await message in superClient.messageStream { try Task.checkCancellation() await onMessage(message) } } group.addTask { while true { try await Task.sleep(for: .seconds(5)) try Task.checkCancellation() await superClient.send(type: .ping, data: Data()) } } _ = try await group.next() } } private func cleanup(_ superClient: SDLSuperClient) async { await superClient.stop() if self.superClient === superClient { self.superClient = nil } SDLLogger.log("[SDLSuperService] cleanup") } }