punchnet-macos/Tun/DNS/DNSCloudService.swift
2026-05-28 14:15:26 +08:00

87 lines
2.1 KiB
Swift

import Foundation
actor DNSCloudService {
private let serverIP: String
private var onEvent: DNSEventHandler = { _ in }
private var currentClient: DNSCloudClient?
private var generation: UInt64 = 0
init(serverIP: String) {
self.serverIP = serverIP
}
func updateEventHandler(_ onEvent: @escaping DNSEventHandler) {
self.onEvent = onEvent
}
func run() async throws {
let generation = self.nextGeneration()
let client = DNSCloudClient(serverIP: self.serverIP, port: 15353)
self.currentClient = client
defer {
self.clearCurrent(client, generation: generation)
}
do {
let onEvent = self.onEvent
try await withThrowingTaskGroup(of: Void.self) { group in
defer {
group.cancelAll()
}
group.addTask {
try await client.run()
}
group.addTask {
for try await packet in client.packetFlow {
try Task.checkCancellation()
await onEvent(.packet(packet))
}
}
_ = try await group.next()
}
await client.stop()
} catch is CancellationError {
await client.stop()
throw CancellationError()
} catch {
await client.stop()
throw error
}
}
func stop() async {
self.generation &+= 1
let client = self.currentClient
self.currentClient = nil
await client?.stop()
}
func forward(ipPacketData: Data) async {
await self.currentClient?.forward(ipPacketData: ipPacketData)
}
private func nextGeneration() -> UInt64 {
self.generation &+= 1
return self.generation
}
private func clearCurrent(_ client: DNSCloudClient, generation: UInt64) {
guard self.generation == generation else {
return
}
if self.currentClient === client {
self.currentClient = nil
}
}
}