punchnet-macos/Tun/Punchnet/SDLNetworkMonitor.swift
2025-08-25 15:43:17 +08:00

65 lines
1.9 KiB
Swift

//
// SDLNetworkMonitor.swift
// Tun
//
// Created by on 2024/5/16.
//
import Foundation
import Network
import Combine
//
class SDLNetworkMonitor: @unchecked Sendable {
private var monitor: NWPathMonitor
private var interfaceType: NWInterface.InterfaceType?
private let publisher = PassthroughSubject<NWInterface.InterfaceType, Never>()
private var cancel: AnyCancellable?
public let eventStream: AsyncStream<MonitorEvent>
private let eventContinuation: AsyncStream<MonitorEvent>.Continuation
enum MonitorEvent {
case changed
case unreachable
}
init() {
self.monitor = NWPathMonitor()
(self.eventStream , self.eventContinuation) = AsyncStream.makeStream(of: MonitorEvent.self, bufferingPolicy: .unbounded)
}
func start() {
self.monitor.pathUpdateHandler = {path in
if path.status == .satisfied {
if path.usesInterfaceType(.wifi) {
self.publisher.send(.wifi)
} else if path.usesInterfaceType(.cellular) {
self.publisher.send(.cellular)
} else if path.usesInterfaceType(.wiredEthernet) {
self.publisher.send(.wiredEthernet)
}
} else {
self.eventContinuation.yield(.unreachable)
self.interfaceType = nil
}
}
self.monitor.start(queue: DispatchQueue.global())
self.cancel = publisher.throttle(for: 5.0, scheduler: DispatchQueue.global(), latest: true)
.sink { type in
if self.interfaceType != nil && self.interfaceType != type {
self.eventContinuation.yield(.changed)
}
self.interfaceType = type
}
}
deinit {
self.monitor.cancel()
self.cancel?.cancel()
self.eventContinuation.finish()
}
}