fix Service

This commit is contained in:
anlicheng 2026-06-22 14:42:34 +08:00
parent 3e90e3788a
commit 5b990535fa
6 changed files with 344 additions and 146 deletions

View File

@ -287,28 +287,20 @@ actor SDLContextActor {
}
group.addTask {
try await Self.runRestarting(name: "udpHoleService") {
try await udpHoleService.run()
}
}
group.addTask {
try await Self.runRestarting(name: "udpHoleV6Service") {
try await udpHoleV6Service.run()
}
}
group.addTask {
try await Self.runRestarting(name: "dnsCloudService") {
try await dnsCloudService.run()
}
}
group.addTask {
try await Self.runRestarting(name: "dnsLocalService") {
try await dnsLocalService.run()
}
}
group.addTask {
try await puncherActor.runCleanup()
@ -618,27 +610,6 @@ extension SDLContextActor {
extension SDLContextActor {
private static func runRestarting(
name: String,
retryDelay: Duration = .seconds(5),
operation: @escaping @Sendable () async throws -> Void
) async throws {
while !Task.isCancelled {
do {
try Task.checkCancellation()
try await operation()
SDLLogger.log("[SDLContext] worker \(name) ended, will restart", category: .context)
} catch is CancellationError {
SDLLogger.log("[SDLContext] worker \(name) cancelled", category: .context)
throw CancellationError()
} catch {
SDLLogger.log("[SDLContext] worker \(name) crashed: \(error.localizedDescription), will restart", category: .context)
}
try await Task.sleep(for: retryDelay)
}
}
private static func runPeriodic(
name: String,
interval: Duration,

View File

@ -5,9 +5,14 @@ actor DNSCloudService {
private var onEvent: DNSEventHandler = { _ in }
private var currentClient: DNSCloudClient?
private var isRunning = false
private var isStopping = false
private var needsImmediateRestart = false
private let retryDelay: Duration
init(serverIP: String) {
init(serverIP: String, retryDelay: Duration = .seconds(5)) {
self.serverIP = serverIP
self.retryDelay = retryDelay
}
func updateEventHandler(_ onEvent: @escaping DNSEventHandler) {
@ -15,14 +20,95 @@ actor DNSCloudService {
}
func run() async throws {
guard !self.isRunning else {
return
}
self.isRunning = true
self.isStopping = false
defer {
self.isRunning = false
self.currentClient = nil
}
while !Task.isCancelled, !self.isStopping {
let client = DNSCloudClient(serverIP: self.serverIP, port: 15353)
self.currentClient = client
defer {
do {
try await self.run(client: client)
self.clearCurrent(client)
await client.stop()
guard !self.isStopping else {
break
}
do {
SDLLogger.log("[DNSCloudService] dnsCloudClient ended, will restart", category: .dns)
} catch is CancellationError {
self.clearCurrent(client)
await client.stop()
throw CancellationError()
} catch {
self.clearCurrent(client)
await client.stop()
guard !self.isStopping else {
break
}
SDLLogger.log("[DNSCloudService] dnsCloudClient failed: \(error.localizedDescription), will restart", category: .dns)
}
if self.consumeImmediateRestartRequest() {
SDLLogger.log("[DNSCloudService] dnsCloudClient invalidated after wakeup, will restart immediately", category: .dns)
continue
}
try await Task.sleep(for: self.retryDelay)
}
}
func stop() async {
self.isStopping = true
self.needsImmediateRestart = false
await self.invalidateCurrentClient()
}
func recoverAfterWake() async {
guard !self.isStopping else {
return
}
self.needsImmediateRestart = self.currentClient != nil
await self.invalidateCurrentClient()
}
func forward(ipPacketData: Data) async {
await self.currentClient?.forward(ipPacketData: ipPacketData)
}
private func clearCurrent(_ client: DNSCloudClient) {
if self.currentClient === client {
self.currentClient = nil
}
}
private func invalidateCurrentClient() async {
let client = self.currentClient
self.currentClient = nil
await client?.stop()
}
private func consumeImmediateRestartRequest() -> Bool {
let needsImmediateRestart = self.needsImmediateRestart
self.needsImmediateRestart = false
return needsImmediateRestart
}
private func run(client: DNSCloudClient) async throws {
let onEvent = self.onEvent
try await withThrowingTaskGroup(of: Void.self) { group in
@ -43,35 +129,5 @@ actor DNSCloudService {
_ = try await group.next()
}
await client.stop()
} catch is CancellationError {
await client.stop()
throw CancellationError()
} catch {
await client.stop()
throw error
}
}
func stop() async {
let client = self.currentClient
self.currentClient = nil
await client?.stop()
}
func recoverAfterWake() async {
await self.stop()
}
func forward(ipPacketData: Data) async {
await self.currentClient?.forward(ipPacketData: ipPacketData)
}
private func clearCurrent(_ client: DNSCloudClient) {
if self.currentClient === client {
self.currentClient = nil
}
}
}

View File

@ -5,9 +5,14 @@ actor DNSLocalService {
private var onEvent: DNSEventHandler = { _ in }
private var currentClient: DNSLocalClient?
private var isRunning = false
private var isStopping = false
private var needsImmediateRestart = false
private let retryDelay: Duration
init(publicDnsServers: [String]) {
init(publicDnsServers: [String], retryDelay: Duration = .seconds(5)) {
self.publicDnsServers = publicDnsServers
self.retryDelay = retryDelay
}
func updateEventHandler(_ onEvent: @escaping DNSEventHandler) {
@ -15,6 +20,19 @@ actor DNSLocalService {
}
func run() async throws {
guard !self.isRunning else {
return
}
self.isRunning = true
self.isStopping = false
defer {
self.isRunning = false
self.currentClient = nil
}
while !Task.isCancelled, !self.isStopping {
let dnsServer = self.publicDnsServers.randomElement() ?? "223.5.5.5"
let client = DNSLocalClient(host: dnsServer)
self.currentClient = client
@ -25,6 +43,12 @@ actor DNSLocalService {
try await self.run(client: client)
self.clearCurrent(client)
await client.stop()
guard !self.isStopping else {
break
}
SDLLogger.log("[DNSLocalService] dnsLocalClient ended, will restart", category: .dns)
} catch is CancellationError {
self.clearCurrent(client)
await client.stop()
@ -32,19 +56,36 @@ actor DNSLocalService {
} catch {
self.clearCurrent(client)
await client.stop()
throw error
guard !self.isStopping else {
break
}
SDLLogger.log("[DNSLocalService] dnsLocalClient failed: \(error.localizedDescription), will restart", category: .dns)
}
if self.consumeImmediateRestartRequest() {
SDLLogger.log("[DNSLocalService] dnsLocalClient invalidated after wakeup, will restart immediately", category: .dns)
continue
}
try await Task.sleep(for: self.retryDelay)
}
}
func stop() async {
let client = self.currentClient
self.currentClient = nil
await client?.stop()
self.isStopping = true
self.needsImmediateRestart = false
await self.invalidateCurrentClient()
}
func recoverAfterWake() async {
await self.stop()
guard !self.isStopping else {
return
}
self.needsImmediateRestart = self.currentClient != nil
await self.invalidateCurrentClient()
}
func query(tracker: DNSLocalClient.DNSTracker, dnsPayload: Data) async {
@ -79,4 +120,17 @@ actor DNSLocalService {
self.currentClient = nil
}
}
private func invalidateCurrentClient() async {
let client = self.currentClient
self.currentClient = nil
await client?.stop()
}
private func consumeImmediateRestartRequest() -> Bool {
let needsImmediateRestart = self.needsImmediateRestart
self.needsImmediateRestart = false
return needsImmediateRestart
}
}

View File

@ -53,6 +53,11 @@ actor SDLSuperService {
try await session.run()
self.clearCurrent(session, generation: generation)
await session.stop()
guard !self.isStopping else {
break
}
SDLLogger.log("[SDLSuperService] session ended, will restart", category: .super)
} catch is CancellationError {
self.clearCurrent(session, generation: generation)
@ -80,6 +85,7 @@ actor SDLSuperService {
func stop() async {
self.isStopping = true
self.needsImmediateRestart = false
await self.invalidateCurrentSession()
}
@ -88,7 +94,7 @@ actor SDLSuperService {
return
}
self.needsImmediateRestart = true
self.needsImmediateRestart = self.currentSession != nil
await self.invalidateCurrentSession()
}

View File

@ -18,9 +18,14 @@ actor SDLUDPHoleService {
private var onData: DataHandler = { _ in }
private var currentSession: SDLUDPHoleSession?
private var generation: UInt64 = 0
private var isRunning = false
private var isStopping = false
private var needsImmediateRestart = false
private let retryDelay: Duration
init(proberActor: SDLNATProberActor) {
init(proberActor: SDLNATProberActor, retryDelay: Duration = .seconds(5)) {
self.proberActor = proberActor
self.retryDelay = retryDelay
}
func updateHandlers(onEvent: @escaping EventHandler, onData: @escaping DataHandler) {
@ -29,6 +34,19 @@ actor SDLUDPHoleService {
}
func run() async throws {
guard !self.isRunning else {
return
}
self.isRunning = true
self.isStopping = false
defer {
self.isRunning = false
self.currentSession = nil
}
while !Task.isCancelled, !self.isStopping {
let generation = self.nextGeneration()
let session = SDLUDPHoleSession(
proberActor: self.proberActor,
@ -44,6 +62,12 @@ actor SDLUDPHoleService {
try await session.run()
self.clearCurrent(session, generation: generation)
await session.stop()
guard !self.isStopping else {
break
}
SDLLogger.log("[SDLUDPHoleService] session ended, will restart", category: .udpHole)
} catch is CancellationError {
self.clearCurrent(session, generation: generation)
await session.stop()
@ -51,22 +75,36 @@ actor SDLUDPHoleService {
} catch {
self.clearCurrent(session, generation: generation)
await session.stop()
throw error
guard !self.isStopping else {
break
}
SDLLogger.log("[SDLUDPHoleService] session failed: \(error.localizedDescription), will restart", category: .udpHole)
}
if self.consumeImmediateRestartRequest() {
SDLLogger.log("[SDLUDPHoleService] session invalidated after wakeup, will restart immediately", category: .udpHole)
continue
}
try await Task.sleep(for: self.retryDelay)
}
}
func stop() async {
self.generation &+= 1
let session = self.currentSession
self.currentSession = nil
await session?.stop()
await self.proberActor.cancelAll()
self.isStopping = true
self.needsImmediateRestart = false
await self.invalidateCurrentSession()
}
func recoverAfterWake() async {
await self.stop()
guard !self.isStopping else {
return
}
self.needsImmediateRestart = self.currentSession != nil
await self.invalidateCurrentSession()
}
func send(type: SDLPacketType, data: Data, remoteAddress: SocketAddress) async {
@ -78,6 +116,22 @@ actor SDLUDPHoleService {
return self.generation
}
private func invalidateCurrentSession() async {
self.generation &+= 1
let session = self.currentSession
self.currentSession = nil
await session?.stop()
await self.proberActor.cancelAll()
}
private func consumeImmediateRestartRequest() -> Bool {
let needsImmediateRestart = self.needsImmediateRestart
self.needsImmediateRestart = false
return needsImmediateRestart
}
private func clearCurrent(_ session: SDLUDPHoleSession, generation: UInt64) {
guard self.generation == generation else {
return

View File

@ -9,6 +9,14 @@ actor SDLUDPHoleV6Service {
private var onData: DataHandler = { _ in }
private var currentSession: SDLUDPHoleV6Session?
private var generation: UInt64 = 0
private var isRunning = false
private var isStopping = false
private var needsImmediateRestart = false
private let retryDelay: Duration
init(retryDelay: Duration = .seconds(5)) {
self.retryDelay = retryDelay
}
func updateHandlers(onEvent: @escaping EventHandler, onData: @escaping DataHandler) {
self.onEvent = onEvent
@ -16,6 +24,19 @@ actor SDLUDPHoleV6Service {
}
func run() async throws {
guard !self.isRunning else {
return
}
self.isRunning = true
self.isStopping = false
defer {
self.isRunning = false
self.currentSession = nil
}
while !Task.isCancelled, !self.isStopping {
let generation = self.nextGeneration()
let session = SDLUDPHoleV6Session(
onEvent: { [weak self] event in
@ -30,6 +51,12 @@ actor SDLUDPHoleV6Service {
try await session.run()
self.clearCurrent(session, generation: generation)
await session.stop()
guard !self.isStopping else {
break
}
SDLLogger.log("[SDLUDPHoleV6Service] session ended, will restart", category: .udpHole)
} catch is CancellationError {
self.clearCurrent(session, generation: generation)
await session.stop()
@ -37,21 +64,36 @@ actor SDLUDPHoleV6Service {
} catch {
self.clearCurrent(session, generation: generation)
await session.stop()
throw error
guard !self.isStopping else {
break
}
SDLLogger.log("[SDLUDPHoleV6Service] session failed: \(error.localizedDescription), will restart", category: .udpHole)
}
if self.consumeImmediateRestartRequest() {
SDLLogger.log("[SDLUDPHoleV6Service] session invalidated after wakeup, will restart immediately", category: .udpHole)
continue
}
try await Task.sleep(for: self.retryDelay)
}
}
func stop() async {
self.generation &+= 1
let session = self.currentSession
self.currentSession = nil
await session?.stop()
self.isStopping = true
self.needsImmediateRestart = false
await self.invalidateCurrentSession()
}
func recoverAfterWake() async {
await self.stop()
guard !self.isStopping else {
return
}
self.needsImmediateRestart = self.currentSession != nil
await self.invalidateCurrentSession()
}
func send(type: SDLPacketType, data: Data, remoteAddress: SocketAddress) async {
@ -63,6 +105,21 @@ actor SDLUDPHoleV6Service {
return self.generation
}
private func invalidateCurrentSession() async {
self.generation &+= 1
let session = self.currentSession
self.currentSession = nil
await session?.stop()
}
private func consumeImmediateRestartRequest() -> Bool {
let needsImmediateRestart = self.needsImmediateRestart
self.needsImmediateRestart = false
return needsImmediateRestart
}
private func clearCurrent(_ session: SDLUDPHoleV6Session, generation: UInt64) {
guard self.generation == generation else {
return