You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
55 lines
1.9 KiB
55 lines
1.9 KiB
import Foundation
|
|
import Network
|
|
|
|
/// Network interfaces that services can be bound to (e.g. en7 = technical network).
|
|
public enum NetworkInterfaces {
|
|
public struct Info: Hashable, Sendable, Identifiable {
|
|
public var id: String { name }
|
|
public let name: String
|
|
public let kind: String
|
|
}
|
|
|
|
/// Currently available interfaces (wired, Wi-Fi, other), excluding loopback.
|
|
public static func available() async -> [Info] {
|
|
await withCheckedContinuation { continuation in
|
|
let monitor = NWPathMonitor()
|
|
let once = OnceFlag()
|
|
monitor.pathUpdateHandler = { path in
|
|
guard once.claim() else { return }
|
|
monitor.cancel()
|
|
continuation.resume(returning: path.availableInterfaces
|
|
.filter { $0.type != .loopback }
|
|
.map { Info(name: $0.name, kind: describe($0.type)) })
|
|
}
|
|
monitor.start(queue: .global(qos: .utility))
|
|
}
|
|
}
|
|
|
|
static func interface(named name: String) async -> NWInterface? {
|
|
await withCheckedContinuation { continuation in
|
|
let monitor = NWPathMonitor()
|
|
let once = OnceFlag()
|
|
monitor.pathUpdateHandler = { path in
|
|
guard once.claim() else { return }
|
|
monitor.cancel()
|
|
continuation.resume(returning: path.availableInterfaces.first { $0.name == name })
|
|
}
|
|
monitor.start(queue: .global(qos: .utility))
|
|
}
|
|
}
|
|
|
|
private static func describe(_ type: NWInterface.InterfaceType) -> String {
|
|
switch type {
|
|
case .wiredEthernet: "Ethernet"
|
|
case .wifi: "WLAN"
|
|
default: "Andere"
|
|
}
|
|
}
|
|
}
|
|
|
|
final class OnceFlag: @unchecked Sendable {
|
|
private let lock = NSLock()
|
|
private var done = false
|
|
func claim() -> Bool { lock.withLock { defer { done = true }; return !done } }
|
|
}
|