import Foundation import Network import NetworkExtension import Combine @MainActor final class LANMonitor: ObservableObject { static let shared = LANMonitor() @Published private(set) var isOnNetwork: Bool = false @Published private(set) var currentSSID: String? = nil private let monitor = NWPathMonitor() private let queue = DispatchQueue(label: "com.albert.nasbackup.lan", qos: .utility) var onTrustedNetworkJoined: ((String) -> Void)? private init() {} func start() { monitor.pathUpdateHandler = { [weak self] path in guard let self else { return } Task { @MainActor in let satisfied = path.status == .satisfied self.isOnNetwork = satisfied if satisfied { await self.checkSSID() } else { self.currentSSID = nil } } } monitor.start(queue: queue) } func stop() { monitor.cancel() } private func checkSSID() async { let ssid = await fetchCurrentSSID() self.currentSSID = ssid } func fetchCurrentSSID() async -> String? { await withCheckedContinuation { continuation in NEHotspotNetwork.fetchCurrent { network in continuation.resume(returning: network?.ssid) } } } func checkAndTriggerIfTrusted(trustedSSIDs: [String]) async { let ssid = await fetchCurrentSSID() guard let ssid, trustedSSIDs.contains(ssid) else { return } onTrustedNetworkJoined?(ssid) } }