punchnet-macos/Tun/Punchnet/Super/SDLSuperService.swift
2026-05-21 13:42:43 +08:00

141 lines
3.8 KiB
Swift

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<Void, Never>?
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 await 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")
}
}
actor SDLSuperServiceProxy {
private var superService: SDLSuperService?
private var generation: UInt64 = 0
func replace(_ superService: SDLSuperService?) async {
self.generation &+= 1
let oldSuperService = self.superService
self.superService = superService
if oldSuperService !== superService {
await oldSuperService?.stop()
}
}
func stop() async {
self.generation &+= 1
let superService = self.superService
self.superService = nil
await superService?.stop()
}
func send(type: SDLPacketType, data: Data) async {
await self.superService?.send(type: type, data: data)
}
}