解决网络状态变化的问题

This commit is contained in:
anlicheng 2026-04-29 16:33:27 +08:00
parent 779947677c
commit e68bf7e106
4 changed files with 140 additions and 11 deletions

View File

@ -86,7 +86,7 @@ actor SDLContextActor {
nonisolated private let arpServer: ArpServer
//
private var monitor: SDLNetworkMonitor?
private var monitor: SDLPathMonitor?
private var monitorWorker: Task<Void, Never>?
// socket
@ -338,20 +338,25 @@ actor SDLContextActor {
self.monitorWorker = nil
// monitor
let monitor = SDLNetworkMonitor()
let monitor = SDLPathMonitor()
monitor.start()
SDLLogger.log("[SDLContext] monitor started")
self.monitor = monitor
self.monitorWorker = Task.detached {
for await event in monitor.eventStream {
switch event {
case .changed:
// nat
await self.probeNatType()
SDLLogger.log("didNetworkPathChanged, nat type is:")
case .unreachable:
SDLLogger.log("didNetworkPathUnreachable")
self.monitorWorker = Task {
for await status in monitor.statusStream() {
switch status {
case .satisfied:
SDLLogger.log("[Path] stable satisfied", for: .debug)
// await contextActor.networkPathDidBecomeSatisfied(snapshot)
case .unsatisfied:
SDLLogger.log("[Path] stable unsatisfied", for: .debug)
// await contextActor.networkPathDidBecomeUnsatisfied(snapshot)
case .requiresConnection:
SDLLogger.log("[Path] stable requiresConnection", for: .debug)
@unknown default:
SDLLogger.log("[Path] stable unknown", for: .debug)
}
}
}

View File

@ -0,0 +1,54 @@
//
// SDLPathDebounceActor.swift
// punchnet
//
// Created by on 2026/4/29.
//
import Foundation
import Network
actor SDLPathDebounceActor {
private var lastSnapshot: SDLPathSnapshot?
private var debounceTask: Task<Void, Never>?
private let delay: Duration
public let statusStream: AsyncStream<NWPath.Status>
private let statusCont: AsyncStream<NWPath.Status>.Continuation
init(delay: Duration = .seconds(2)) {
self.delay = delay
let (stream, cont) = AsyncStream.makeStream(of: NWPath.Status.self)
self.statusStream = stream
self.statusCont = cont
}
func submit(_ snapshot: SDLPathSnapshot) {
guard snapshot != lastSnapshot else {
return
}
self.lastSnapshot = snapshot
self.debounceTask?.cancel()
self.debounceTask = Task { [delay] in
try? await Task.sleep(for: delay)
guard !Task.isCancelled else {
return
}
await self.handleStableSnapshot(snapshot)
}
}
private func handleStableSnapshot(_ snapshot: SDLPathSnapshot) async {
self.statusCont.yield(snapshot.status)
}
func stop() {
debounceTask?.cancel()
debounceTask = nil
}
}

View File

@ -0,0 +1,38 @@
//
// SDLPathMonitor.swift
// punchnet
//
// Created by on 2026/4/29.
//
import Foundation
import Network
final class SDLPathMonitor {
private let monitor = NWPathMonitor()
private let queue = DispatchQueue(label: "com.sdlan.path-monitor")
private let debouncer = SDLPathDebounceActor(delay: .seconds(2))
func start() {
monitor.pathUpdateHandler = { path in
let snapshot = SDLPathSnapshot(path)
Task {
await self.debouncer.submit(snapshot)
}
}
monitor.start(queue: queue)
}
func statusStream() -> AsyncStream<NWPath.Status> {
return self.debouncer.statusStream
}
func stop() {
Task {
await debouncer.stop()
}
monitor.cancel()
}
}

View File

@ -0,0 +1,32 @@
//
// PathSnapshot.swift
// punchnet
//
// Created by on 2026/4/29.
//
import Foundation
import Network
struct SDLPathSnapshot: Equatable, Sendable {
let status: NWPath.Status
let isExpensive: Bool
let isConstrained: Bool
let supportsIPv4: Bool
let supportsIPv6: Bool
let supportsDNS: Bool
let usesWiFi: Bool
let usesWired: Bool
let usesCellular: Bool
init(_ path: NWPath) {
self.status = path.status
self.isExpensive = path.isExpensive
self.isConstrained = path.isConstrained
self.supportsIPv4 = path.supportsIPv4
self.supportsIPv6 = path.supportsIPv6
self.supportsDNS = path.supportsDNS
self.usesWiFi = path.usesInterfaceType(.wifi)
self.usesWired = path.usesInterfaceType(.wiredEthernet)
self.usesCellular = path.usesInterfaceType(.cellular)
}
}